curb 0.7.15 → 1.0.0

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/ext/curb_easy.c CHANGED
@@ -25,9 +25,19 @@ static VALUE rbstrAmp;
25
25
 
26
26
  VALUE cCurlEasy;
27
27
 
28
+ // for Ruby 1.8
29
+ #ifndef HAVE_RB_IO_STDIO_FILE
30
+ static FILE * rb_io_stdio_file(rb_io_t *fptr) {
31
+ return fptr->f;
32
+ }
33
+ #endif
28
34
 
29
35
  /* ================== CURL HANDLER FUNCS ==============*/
30
36
 
37
+ static VALUE callback_exception(VALUE unused) {
38
+ return Qfalse;
39
+ }
40
+
31
41
  /* These handle both body and header data */
32
42
  static size_t default_data_handler(char *stream,
33
43
  size_t size,
@@ -92,6 +102,25 @@ static size_t read_data_handler(void *ptr,
92
102
  }
93
103
  }
94
104
 
105
+ int seek_data_handler(ruby_curl_easy *rbce,
106
+ curl_off_t offset,
107
+ int origin) {
108
+
109
+ VALUE upload = rb_easy_get("upload");
110
+ VALUE stream = ruby_curl_upload_stream_get(upload);
111
+
112
+ if (rb_respond_to(stream, rb_intern("seek"))) {
113
+ rb_funcall(stream, rb_intern("seek"), 2, SEEK_SET, offset);
114
+ } else {
115
+ ruby_curl_upload *rbcu;
116
+ Data_Get_Struct(upload, ruby_curl_upload, rbcu);
117
+ // This OK because curl only uses SEEK_SET as per the documentation
118
+ rbcu->offset = offset;
119
+ }
120
+
121
+ return 0;
122
+ }
123
+
95
124
  static size_t proc_data_handler(char *stream,
96
125
  size_t size,
97
126
  size_t nmemb,
@@ -111,27 +140,81 @@ static size_t proc_data_handler(char *stream,
111
140
  }
112
141
  }
113
142
 
143
+ static size_t proc_data_handler_body(char *stream,
144
+ size_t size,
145
+ size_t nmemb,
146
+ ruby_curl_easy *rbce)
147
+ {
148
+ size_t ret;
149
+ rbce->callback_active = 1;
150
+ ret = proc_data_handler(stream, size, nmemb, rb_easy_get("body_proc"));
151
+ rbce->callback_active = 0;
152
+ return ret;
153
+ }
154
+ static size_t proc_data_handler_header(char *stream,
155
+ size_t size,
156
+ size_t nmemb,
157
+ ruby_curl_easy *rbce)
158
+ {
159
+ size_t ret;
160
+ rbce->callback_active = 1;
161
+ ret = proc_data_handler(stream, size, nmemb, rb_easy_get("header_proc"));
162
+ rbce->callback_active = 0;
163
+ return ret;
164
+ }
165
+
166
+
167
+ static VALUE call_progress_handler(VALUE ary) {
168
+ return rb_funcall(rb_ary_entry(ary, 0), idCall, 4,
169
+ rb_ary_entry(ary, 1), // rb_float_new(dltotal),
170
+ rb_ary_entry(ary, 2), // rb_float_new(dlnow),
171
+ rb_ary_entry(ary, 3), // rb_float_new(ultotal),
172
+ rb_ary_entry(ary, 4)); // rb_float_new(ulnow));
173
+ }
174
+
114
175
  static int proc_progress_handler(VALUE proc,
115
176
  double dltotal,
116
177
  double dlnow,
117
178
  double ultotal,
118
179
  double ulnow) {
119
180
  VALUE procret;
181
+ VALUE callargs = rb_ary_new2(5);
120
182
 
121
- procret = rb_funcall(proc, idCall, 4, rb_float_new(dltotal),
122
- rb_float_new(dlnow),
123
- rb_float_new(ultotal),
124
- rb_float_new(ulnow));
183
+ rb_ary_store(callargs, 0, proc);
184
+ rb_ary_store(callargs, 1, rb_float_new(dltotal));
185
+ rb_ary_store(callargs, 2, rb_float_new(dlnow));
186
+ rb_ary_store(callargs, 3, rb_float_new(ultotal));
187
+ rb_ary_store(callargs, 4, rb_float_new(ulnow));
188
+
189
+ //v = rb_rescue(range_check, (VALUE)args, range_failed, 0);
190
+ //procret = rb_funcall(proc, idCall, 4, rb_float_new(dltotal),
191
+ // rb_float_new(dlnow),
192
+ // rb_float_new(ultotal),
193
+ // rb_float_new(ulnow));
194
+ procret = rb_rescue(call_progress_handler, callargs, callback_exception, Qnil);
125
195
 
126
196
  return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
127
197
  }
128
198
 
199
+ static VALUE call_debug_handler(VALUE ary) {
200
+ return rb_funcall(rb_ary_entry(ary, 0), idCall, 2,
201
+ rb_ary_entry(ary, 1), // INT2NUM(type),
202
+ rb_ary_entry(ary, 2)); // rb_str_new(data, data_len)
203
+ }
129
204
  static int proc_debug_handler(CURL *curl,
130
205
  curl_infotype type,
131
206
  char *data,
132
207
  size_t data_len,
133
208
  VALUE proc) {
134
- rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
209
+ VALUE callargs = rb_ary_new2(3);
210
+ rb_ary_store(callargs, 0, proc);
211
+ rb_ary_store(callargs, 1, INT2NUM(type));
212
+ rb_ary_store(callargs, 2, rb_str_new(data, data_len));
213
+ rb_rescue(call_debug_handler, callargs, callback_exception, Qnil);
214
+ /* no way to indicate to libcurl that we should break out given an exception in the on_debug handler...
215
+ * this means exceptions will be swallowed
216
+ */
217
+ //rb_funcall(proc, idCall, 2, INT2NUM(type), rb_str_new(data, data_len));
135
218
  return 0;
136
219
  }
137
220
 
@@ -146,12 +229,31 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
146
229
  curl_slist_free_all(rbce->curl_headers);
147
230
  }
148
231
 
232
+ if (rbce->curl_proxy_headers) {
233
+ curl_slist_free_all(rbce->curl_proxy_headers);
234
+ }
235
+
149
236
  if (rbce->curl_ftp_commands) {
150
237
  curl_slist_free_all(rbce->curl_ftp_commands);
151
238
  }
152
239
 
240
+ if (rbce->curl_resolve) {
241
+ curl_slist_free_all(rbce->curl_resolve);
242
+ }
243
+
153
244
  if (rbce->curl) {
245
+ /* disable any progress or debug events */
246
+ curl_easy_setopt(rbce->curl, CURLOPT_WRITEFUNCTION, NULL);
247
+ curl_easy_setopt(rbce->curl, CURLOPT_WRITEDATA, NULL);
248
+ curl_easy_setopt(rbce->curl, CURLOPT_HEADERFUNCTION, NULL);
249
+ curl_easy_setopt(rbce->curl, CURLOPT_HEADERDATA, NULL);
250
+ curl_easy_setopt(rbce->curl, CURLOPT_DEBUGFUNCTION, NULL);
251
+ curl_easy_setopt(rbce->curl, CURLOPT_DEBUGDATA, NULL);
252
+ curl_easy_setopt(rbce->curl, CURLOPT_VERBOSE, 0);
253
+ curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
254
+ curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
154
255
  curl_easy_cleanup(rbce->curl);
256
+ rbce->curl = NULL;
155
257
  }
156
258
  }
157
259
 
@@ -166,8 +268,12 @@ void curl_easy_free(ruby_curl_easy *rbce) {
166
268
  static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
167
269
  rbce->opts = rb_hash_new();
168
270
 
271
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
272
+
169
273
  rbce->curl_headers = NULL;
274
+ rbce->curl_proxy_headers = NULL;
170
275
  rbce->curl_ftp_commands = NULL;
276
+ rbce->curl_resolve = NULL;
171
277
 
172
278
  /* various-typed opts */
173
279
  rbce->local_port = 0;
@@ -178,20 +284,25 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
178
284
  rbce->proxy_auth_types = 0;
179
285
  rbce->max_redirs = -1;
180
286
  rbce->timeout = 0;
287
+ rbce->timeout_ms = 0;
181
288
  rbce->connect_timeout = 0;
289
+ rbce->connect_timeout_ms = 0;
182
290
  rbce->dns_cache_timeout = 60;
183
291
  rbce->ftp_response_timeout = 0;
184
292
  rbce->low_speed_limit = 0;
185
293
  rbce->low_speed_time = 0;
294
+ rbce->max_send_speed_large = 0;
295
+ rbce->max_recv_speed_large = 0;
186
296
  rbce->ssl_version = -1;
187
297
  rbce->use_ssl = -1;
188
298
  rbce->ftp_filemethod = -1;
299
+ rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
189
300
 
190
301
  /* bool opts */
191
302
  rbce->proxy_tunnel = 0;
192
303
  rbce->fetch_file_time = 0;
193
304
  rbce->ssl_verify_peer = 1;
194
- rbce->ssl_verify_host = 1;
305
+ rbce->ssl_verify_host = 2;
195
306
  rbce->header_in_body = 0;
196
307
  rbce->use_netrc = 0;
197
308
  rbce->follow_location = 0;
@@ -200,6 +311,20 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
200
311
  rbce->multipart_form_post = 0;
201
312
  rbce->enable_cookies = 0;
202
313
  rbce->ignore_content_length = 0;
314
+ rbce->callback_active = 0;
315
+ }
316
+
317
+ /*
318
+ * Allocate space for a Curl::Easy instance.
319
+ */
320
+ static VALUE ruby_curl_easy_allocate(VALUE klass) {
321
+ ruby_curl_easy *rbce;
322
+ rbce = ALLOC(ruby_curl_easy);
323
+ rbce->curl = NULL;
324
+ rbce->opts = Qnil;
325
+ rbce->multi = Qnil;
326
+ ruby_curl_easy_zero(rbce);
327
+ return Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
203
328
  }
204
329
 
205
330
  /*
@@ -208,19 +333,18 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
208
333
  * Curl::Easy.new(url = nil) => #<Curl::Easy...>
209
334
  * Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
210
335
  *
211
- * Create a new Curl::Easy instance, optionally supplying the URL.
336
+ * Initialize a new Curl::Easy instance, optionally supplying the URL.
212
337
  * The block form allows further configuration to be supplied before
213
338
  * the instance is returned.
214
339
  */
215
- static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
340
+ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
216
341
  CURLcode ecode;
217
342
  VALUE url, blk;
218
- VALUE new_curl;
219
343
  ruby_curl_easy *rbce;
220
344
 
221
345
  rb_scan_args(argc, argv, "01&", &url, &blk);
222
346
 
223
- rbce = ALLOC(ruby_curl_easy);
347
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
224
348
 
225
349
  /* handler */
226
350
  rbce->curl = curl_easy_init();
@@ -228,26 +352,26 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
228
352
  rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
229
353
  }
230
354
 
231
- new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
232
-
233
355
  rbce->multi = Qnil;
234
356
  rbce->opts = Qnil;
235
357
 
236
358
  ruby_curl_easy_zero(rbce);
237
359
 
360
+ curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
361
+
238
362
  rb_easy_set("url", url);
239
363
 
240
- /* set the new_curl pointer to the curl handle */
241
- ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)new_curl);
364
+ /* set the pointer to the curl handle */
365
+ ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
242
366
  if (ecode != CURLE_OK) {
243
367
  raise_curl_easy_error_exception(ecode);
244
368
  }
245
369
 
246
370
  if (blk != Qnil) {
247
- rb_funcall(blk, idCall, 1, new_curl);
371
+ rb_funcall(blk, idCall, 1, self);
248
372
  }
249
373
 
250
- return new_curl;
374
+ return self;
251
375
  }
252
376
 
253
377
  /*
@@ -267,7 +391,11 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
267
391
  memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
268
392
  newrbce->curl = curl_easy_duphandle(rbce->curl);
269
393
  newrbce->curl_headers = NULL;
394
+ newrbce->curl_proxy_headers = NULL;
270
395
  newrbce->curl_ftp_commands = NULL;
396
+ newrbce->curl_resolve = NULL;
397
+
398
+ curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
271
399
 
272
400
  return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
273
401
  }
@@ -277,7 +405,7 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
277
405
  * easy.close => nil
278
406
  *
279
407
  * Close the Curl::Easy instance. Any open connections are closed
280
- * The easy handle is reinitialized. If a previous multi handle was
408
+ * The easy handle is reinitialized. If a previous multi handle was
281
409
  * open it is set to nil and will be cleared after a GC.
282
410
  */
283
411
  static VALUE ruby_curl_easy_close(VALUE self) {
@@ -286,6 +414,10 @@ static VALUE ruby_curl_easy_close(VALUE self) {
286
414
 
287
415
  Data_Get_Struct(self, ruby_curl_easy, rbce);
288
416
 
417
+ if (rbce->callback_active) {
418
+ rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
419
+ }
420
+
289
421
  ruby_curl_easy_free(rbce);
290
422
 
291
423
  /* reinit the handle */
@@ -324,12 +456,19 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
324
456
  ruby_curl_easy *rbce;
325
457
  VALUE opts_dup;
326
458
  Data_Get_Struct(self, ruby_curl_easy, rbce);
459
+
460
+ if (rbce->callback_active) {
461
+ rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
462
+ }
463
+
327
464
  opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
328
465
 
329
466
  curl_easy_reset(rbce->curl);
330
467
  ruby_curl_easy_zero(rbce);
331
468
 
332
- /* rest clobbers the private setting, so reset it to self */
469
+ curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
470
+
471
+ /* reset clobbers the private setting, so reset it to self */
333
472
  ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
334
473
  if (ecode != CURLE_OK) {
335
474
  raise_curl_easy_error_exception(ecode);
@@ -341,24 +480,18 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
341
480
  rbce->curl_headers = NULL;
342
481
  }
343
482
 
483
+ /* Free everything up */
484
+ if (rbce->curl_proxy_headers) {
485
+ curl_slist_free_all(rbce->curl_proxy_headers);
486
+ rbce->curl_proxy_headers = NULL;
487
+ }
488
+
344
489
  return opts_dup;
345
490
  }
346
491
 
347
492
 
348
493
  /* ================ OBJ ATTRIBUTES ==================*/
349
494
 
350
- /*
351
- * call-seq:
352
- * easy.url = "http://some.url/" => "http://some.url/"
353
- *
354
- * Set the URL for subsequent calls to +perform+. It is acceptable
355
- * (and even recommended) to reuse Curl::Easy instances by reassigning
356
- * the URL between calls to +perform+.
357
- */
358
- static VALUE ruby_curl_easy_url_set(VALUE self, VALUE url) {
359
- CURB_OBJECT_HSETTER(ruby_curl_easy, url);
360
- }
361
-
362
495
  /*
363
496
  * call-seq:
364
497
  * easy.url => string
@@ -369,35 +502,6 @@ static VALUE ruby_curl_easy_url_get(VALUE self) {
369
502
  CURB_OBJECT_HGETTER(ruby_curl_easy, url);
370
503
  }
371
504
 
372
- /*
373
- * call-seq:
374
- * easy.proxy_url = string => string
375
- *
376
- * Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
377
- * The URL should specify the the host name or dotted IP address. To specify
378
- * port number in this string, append :[port] to the end of the host name.
379
- * The proxy string may be prefixed with [protocol]:// since any such prefix
380
- * will be ignored. The proxy's port number may optionally be specified with
381
- * the separate option proxy_port .
382
- *
383
- * When you tell the library to use an HTTP proxy, libcurl will transparently
384
- * convert operations to HTTP even if you specify an FTP URL etc. This may have
385
- * an impact on what other features of the library you can use, such as
386
- * FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
387
- * tunneling is activated with proxy_tunnel = true.
388
- *
389
- * libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
390
- * *all_proxy* etc, if any of those is set. The proxy_url option does however
391
- * override any possibly set environment variables.
392
- *
393
- * Starting with libcurl 7.14.1, the proxy host string given in environment
394
- * variables can be specified the exact same way as the proxy can be set with
395
- * proxy_url, including protocol prefix (http://) and embedded user + password.
396
- */
397
- static VALUE ruby_curl_easy_proxy_url_set(VALUE self, VALUE proxy_url) {
398
- CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
399
- }
400
-
401
505
  /*
402
506
  * call-seq:
403
507
  * easy.proxy_url => string
@@ -434,6 +538,10 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
434
538
  CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
435
539
  }
436
540
 
541
+ static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
542
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_headers);
543
+ }
544
+
437
545
  /*
438
546
  * call-seq:
439
547
  * easy.headers => Hash, Array or Str
@@ -444,42 +552,55 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
444
552
  ruby_curl_easy *rbce;
445
553
  VALUE headers;
446
554
  Data_Get_Struct(self, ruby_curl_easy, rbce);
447
- headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
555
+ headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
448
556
  if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
449
557
  return headers;
450
558
  }
451
559
 
452
560
  /*
453
561
  * call-seq:
454
- * easy.interface = string => string
562
+ * easy.proxy_headers = "Header: val" => "Header: val"
563
+ * easy.proxy_headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
564
+ * easy.proxy_headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
455
565
  *
456
- * Set the interface name to use as the outgoing network interface.
457
- * The name can be an interface name, an IP address or a host name.
566
+ *
567
+ * For example to set a standard or custom header:
568
+ *
569
+ * easy.proxy_headers["MyHeader"] = "myval"
570
+ *
571
+ * To remove a standard header (this is useful when removing libcurls default
572
+ * 'Expect: 100-Continue' header when using HTTP form posts):
573
+ *
574
+ * easy.proxy_headers["Expect"] = ''
575
+ *
576
+ * Anything passed to libcurl as a header will be converted to a string during
577
+ * the perform step.
458
578
  */
459
- static VALUE ruby_curl_easy_interface_set(VALUE self, VALUE interface_hm) {
460
- CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
461
- }
462
579
 
463
580
  /*
464
581
  * call-seq:
465
- * easy.interface => string
582
+ * easy.proxy_headers => Hash, Array or Str
466
583
  *
467
- * Obtain the interface name that is used as the outgoing network interface.
468
- * The name can be an interface name, an IP address or a host name.
584
+ * Obtain the custom HTTP proxy_headers for following requests.
469
585
  */
470
- static VALUE ruby_curl_easy_interface_get(VALUE self) {
471
- CURB_OBJECT_HGETTER(ruby_curl_easy, interface_hm);
586
+ static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
587
+ ruby_curl_easy *rbce;
588
+ VALUE proxy_headers;
589
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
590
+ proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
591
+ if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
592
+ return proxy_headers;
472
593
  }
473
594
 
474
595
  /*
475
596
  * call-seq:
476
- * easy.userpwd = string => string
597
+ * easy.interface => string
477
598
  *
478
- * Set the username/password string to use for subsequent calls to +perform+.
479
- * The supplied string should have the form "username:password"
599
+ * Obtain the interface name that is used as the outgoing network interface.
600
+ * The name can be an interface name, an IP address or a host name.
480
601
  */
481
- static VALUE ruby_curl_easy_userpwd_set(VALUE self, VALUE userpwd) {
482
- CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
602
+ static VALUE ruby_curl_easy_interface_get(VALUE self) {
603
+ CURB_OBJECT_HGETTER(ruby_curl_easy, interface_hm);
483
604
  }
484
605
 
485
606
  /*
@@ -493,18 +614,6 @@ static VALUE ruby_curl_easy_userpwd_get(VALUE self) {
493
614
  CURB_OBJECT_HGETTER(ruby_curl_easy, userpwd);
494
615
  }
495
616
 
496
- /*
497
- * call-seq:
498
- * easy.proxypwd = string => string
499
- *
500
- * Set the username/password string to use for proxy connection during
501
- * subsequent calls to +perform+. The supplied string should have the
502
- * form "username:password"
503
- */
504
- static VALUE ruby_curl_easy_proxypwd_set(VALUE self, VALUE proxypwd) {
505
- CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
506
- }
507
-
508
617
  /*
509
618
  * call-seq:
510
619
  * easy.proxypwd => string
@@ -517,19 +626,6 @@ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
517
626
  CURB_OBJECT_HGETTER(ruby_curl_easy, proxypwd);
518
627
  }
519
628
 
520
-
521
- /*
522
- * call-seq:
523
- * easy.cookies = "name1=content1; name2=content2;" => string
524
- *
525
- * Set cookies to be sent by this Curl::Easy instance. The format of the string should
526
- * be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
527
- * Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
528
- */
529
- static VALUE ruby_curl_easy_cookies_set(VALUE self, VALUE cookies) {
530
- CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
531
- }
532
-
533
629
  /*
534
630
  * call-seq:
535
631
  * easy.cookies => "name1=content1; name2=content2;"
@@ -540,19 +636,6 @@ static VALUE ruby_curl_easy_cookies_get(VALUE self) {
540
636
  CURB_OBJECT_HGETTER(ruby_curl_easy, cookies);
541
637
  }
542
638
 
543
- /*
544
- * call-seq:
545
- * easy.cookiefile = string => string
546
- *
547
- * Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
548
- *
549
- * *Note* that you must set enable_cookies true to enable the cookie
550
- * engine, or this option will be ignored.
551
- */
552
- static VALUE ruby_curl_easy_cookiefile_set(VALUE self, VALUE cookiefile) {
553
- CURB_OBJECT_HSETTER(ruby_curl_easy, cookiefile);
554
- }
555
-
556
639
  /*
557
640
  * call-seq:
558
641
  * easy.cookiefile => string
@@ -563,20 +646,6 @@ static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
563
646
  CURB_OBJECT_HGETTER(ruby_curl_easy, cookiefile);
564
647
  }
565
648
 
566
- /*
567
- * call-seq:
568
- * easy.cookiejar = string => string
569
- *
570
- * Set a cookiejar file to use for this Curl::Easy instance.
571
- * Cookies from the response will be written into this file.
572
- *
573
- * *Note* that you must set enable_cookies true to enable the cookie
574
- * engine, or this option will be ignored.
575
- */
576
- static VALUE ruby_curl_easy_cookiejar_set(VALUE self, VALUE cookiejar) {
577
- CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
578
- }
579
-
580
649
  /*
581
650
  * call-seq:
582
651
  * easy.cookiejar => string
@@ -730,29 +799,29 @@ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
730
799
  /*
731
800
  * call-seq:
732
801
  * easy.post_body = "some=form%20data&to=send" => string or nil
733
- *
802
+ *
734
803
  * Sets the POST body of this Curl::Easy instance. This is expected to be
735
804
  * URL encoded; no additional processing or encoding is done on the string.
736
805
  * The content-type header will be set to application/x-www-form-urlencoded.
737
- *
806
+ *
738
807
  * This is handy if you want to perform a POST against a Curl::Multi instance.
739
808
  */
740
809
  static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
741
810
  ruby_curl_easy *rbce;
742
811
  CURL *curl;
743
-
812
+
744
813
  char *data;
745
814
  long len;
746
815
 
747
816
  Data_Get_Struct(self, ruby_curl_easy, rbce);
748
-
817
+
749
818
  curl = rbce->curl;
750
-
819
+
751
820
  if ( post_body == Qnil ) {
752
- //rbce->postdata_buffer = Qnil;
753
821
  rb_easy_del("postdata_buffer");
754
-
755
- } else {
822
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
823
+
824
+ } else {
756
825
  if (rb_type(post_body) == T_STRING) {
757
826
  data = StringValuePtr(post_body);
758
827
  len = RSTRING_LEN(post_body);
@@ -765,19 +834,19 @@ static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
765
834
  else {
766
835
  rb_raise(rb_eRuntimeError, "post data must respond_to .to_s");
767
836
  }
768
-
769
- // Store the string, since it has to hang around for the duration of the
837
+
838
+ // Store the string, since it has to hang around for the duration of the
770
839
  // request. See CURLOPT_POSTFIELDS in the libcurl docs.
771
840
  //rbce->postdata_buffer = post_body;
772
841
  rb_easy_set("postdata_buffer", post_body);
773
-
842
+
774
843
  curl_easy_setopt(curl, CURLOPT_POST, 1);
775
844
  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
776
845
  curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
777
-
846
+
778
847
  return post_body;
779
848
  }
780
-
849
+
781
850
  return Qnil;
782
851
  }
783
852
 
@@ -794,7 +863,7 @@ static VALUE ruby_curl_easy_post_body_get(VALUE self) {
794
863
  /*
795
864
  * call-seq:
796
865
  * easy.put_data = data => ""
797
- *
866
+ *
798
867
  * Points this Curl::Easy instance to data to be uploaded via PUT. This
799
868
  * sets the request to a PUT type request - useful if you want to PUT via
800
869
  * a multi handle.
@@ -818,9 +887,15 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
818
887
  curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
819
888
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
820
889
  curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
890
+ #if HAVE_CURLOPT_SEEKFUNCTION
891
+ curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
892
+ #endif
821
893
  curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
894
+ #if HAVE_CURLOPT_SEEKDATA
895
+ curl_easy_setopt(curl, CURLOPT_SEEKDATA, rbce);
896
+ #endif
822
897
 
823
- /*
898
+ /*
824
899
  * we need to set specific headers for the PUT to work... so
825
900
  * convert the internal headers structure to a HASH if one is set
826
901
  */
@@ -834,7 +909,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
834
909
  if (NIL_P(data)) { return data; }
835
910
 
836
911
  headers = rb_easy_get("headers");
837
- if( headers == Qnil ) {
912
+ if( headers == Qnil ) {
838
913
  headers = rb_hash_new();
839
914
  }
840
915
 
@@ -846,14 +921,14 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
846
921
  rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
847
922
  }
848
923
  size = rb_funcall(stat, rb_intern("size"), 0);
849
- curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
924
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, NUM2LONG(size));
850
925
  }
851
926
  else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
852
927
  rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
853
928
  }
854
929
  else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) ) {
855
930
  VALUE size = rb_funcall(rb_hash_aref(headers, rb_str_new2("Content-Length")), rb_intern("to_i"), 0);
856
- curl_easy_setopt(curl, CURLOPT_INFILESIZE, FIX2LONG(size));
931
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, NUM2LONG(size));
857
932
  }
858
933
  }
859
934
  else if (rb_respond_to(data, rb_intern("to_s"))) {
@@ -889,6 +964,25 @@ static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
889
964
  CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_commands);
890
965
  }
891
966
 
967
+ /*
968
+ * call-seq:
969
+ * easy.resolve = [ "example.com:80:127.0.0.1" ] => [ "example.com:80:127.0.0.1" ]
970
+ *
971
+ * Set the resolve list to statically resolve hostnames to IP addresses,
972
+ * bypassing DNS for matching hostname/port combinations.
973
+ */
974
+ static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
975
+ CURB_OBJECT_HSETTER(ruby_curl_easy, resolve);
976
+ }
977
+
978
+ /*
979
+ * call-seq
980
+ * easy.resolve => array or nil
981
+ */
982
+ static VALUE ruby_curl_easy_resolve_get(VALUE self) {
983
+ CURB_OBJECT_HGETTER(ruby_curl_easy, resolve);
984
+ }
985
+
892
986
  /* ================== IMMED ATTRS ==================*/
893
987
 
894
988
  /*
@@ -997,16 +1091,16 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
997
1091
  (!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
998
1092
  (!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
999
1093
  (!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
1000
- (!strncmp("any",node,3)) ? CURLAUTH_ANY : \
1001
- (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : 0
1002
- #else
1094
+ (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
1095
+ (!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
1096
+ #else
1003
1097
  #define CURL_HTTPAUTH_STR_TO_NUM(node) \
1004
1098
  (!strncmp("basic",node,5)) ? CURLAUTH_BASIC : \
1005
1099
  (!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
1006
1100
  (!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
1007
1101
  (!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
1008
- (!strncmp("any",node,3)) ? CURLAUTH_ANY : \
1009
- (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : 0
1102
+ (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
1103
+ (!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
1010
1104
  #endif
1011
1105
  /*
1012
1106
  * call-seq:
@@ -1020,21 +1114,22 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
1020
1114
  static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {//VALUE self, VALUE http_auth_types) {
1021
1115
  ruby_curl_easy *rbce;
1022
1116
  VALUE args_ary;
1023
- int i, len;
1117
+ long i, len;
1024
1118
  char* node = NULL;
1025
- long mask = 0x000000;
1119
+ long mask = 0;
1026
1120
 
1027
1121
  rb_scan_args(argc, argv, "*", &args_ary);
1028
1122
  Data_Get_Struct(self, ruby_curl_easy, rbce);
1029
1123
 
1030
- len = (int)RARRAY_LEN(args_ary);
1124
+ len = RARRAY_LEN(args_ary);
1031
1125
 
1032
- if (len == 1 && (TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM || rb_ary_entry(args_ary,0) == Qnil)) {
1033
- if (rb_ary_entry(args_ary,0) == Qnil) {
1126
+ if (len == 1 && (rb_ary_entry(args_ary,0) == Qnil || TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM ||
1127
+ TYPE(rb_ary_entry(args_ary,0)) == T_BIGNUM)) {
1128
+ if (rb_ary_entry(args_ary,0) == Qnil) {
1034
1129
  rbce->http_auth_types = 0;
1035
1130
  }
1036
1131
  else {
1037
- rbce->http_auth_types = NUM2INT(rb_ary_entry(args_ary,0));
1132
+ rbce->http_auth_types = NUM2LONG(rb_ary_entry(args_ary,0));
1038
1133
  }
1039
1134
  }
1040
1135
  else {
@@ -1047,7 +1142,7 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
1047
1142
  }
1048
1143
  rbce->http_auth_types = mask;
1049
1144
  }
1050
- return INT2NUM(rbce->http_auth_types);
1145
+ return LONG2NUM(rbce->http_auth_types);
1051
1146
  }
1052
1147
 
1053
1148
  /*
@@ -1112,7 +1207,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1112
1207
 
1113
1208
  /*
1114
1209
  * call-seq:
1115
- * easy.timeout = fixnum or nil => fixnum or nil
1210
+ * easy.timeout = float, fixnum or nil => numeric
1116
1211
  *
1117
1212
  * Set the maximum time in seconds that you allow the libcurl transfer
1118
1213
  * operation to take. Normally, name lookups can take a considerable time
@@ -1121,20 +1216,77 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
1121
1216
  *
1122
1217
  * Set to nil (or zero) to disable timeout (it will then only timeout
1123
1218
  * on the system's internal timeouts).
1219
+ *
1220
+ * Uses timeout_ms internally instead of timeout because it allows for
1221
+ * better precision and libcurl will use the last set value when both
1222
+ * timeout and timeout_ms are set.
1223
+ *
1124
1224
  */
1125
- static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout) {
1126
- CURB_IMMED_SETTER(ruby_curl_easy, timeout, 0);
1225
+ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
1226
+ ruby_curl_easy *rbce;
1227
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1228
+
1229
+ if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
1230
+ rbce->timeout_ms = 0;
1231
+ } else {
1232
+ rbce->timeout_ms = (unsigned long)(NUM2DBL(timeout_s) * 1000);
1233
+ }
1234
+
1235
+ return DBL2NUM(rbce->timeout_ms / 1000.0);
1127
1236
  }
1128
1237
 
1129
1238
  /*
1130
1239
  * call-seq:
1131
- * easy.timeout => fixnum or nil
1240
+ * easy.timeout => numeric
1132
1241
  *
1133
1242
  * Obtain the maximum time in seconds that you allow the libcurl transfer
1134
1243
  * operation to take.
1244
+ *
1245
+ * Uses timeout_ms internally instead of timeout.
1246
+ *
1247
+ */
1248
+ static VALUE ruby_curl_easy_timeout_get(VALUE self) {
1249
+ ruby_curl_easy *rbce;
1250
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1251
+ return DBL2NUM(rbce->timeout_ms / 1000.0);
1252
+ }
1253
+
1254
+ /*
1255
+ * call-seq:
1256
+ * easy.timeout_ms = fixnum or nil => fixnum or nil
1257
+ *
1258
+ * Set the maximum time in milliseconds that you allow the libcurl transfer
1259
+ * operation to take. Normally, name lookups can take a considerable time
1260
+ * and limiting operations to less than a few minutes risk aborting
1261
+ * perfectly normal operations.
1262
+ *
1263
+ * Set to nil (or zero) to disable timeout (it will then only timeout
1264
+ * on the system's internal timeouts).
1265
+ */
1266
+ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
1267
+ ruby_curl_easy *rbce;
1268
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1269
+
1270
+ if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
1271
+ rbce->timeout_ms = 0;
1272
+ } else {
1273
+ rbce->timeout_ms = NUM2ULONG(timeout_ms);
1274
+ }
1275
+
1276
+ return ULONG2NUM(rbce->timeout_ms);
1277
+ }
1278
+
1279
+ /*
1280
+ * call-seq:
1281
+ * easy.timeout_ms => fixnum or nil
1282
+ *
1283
+ * Obtain the maximum time in milliseconds that you allow the libcurl transfer
1284
+ * operation to take.
1135
1285
  */
1136
- static VALUE ruby_curl_easy_timeout_get(VALUE self, VALUE timeout) {
1137
- CURB_IMMED_GETTER(ruby_curl_easy, timeout, 0);
1286
+ static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
1287
+ ruby_curl_easy *rbce;
1288
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1289
+ return LONG2NUM(rbce->timeout_ms);
1138
1290
  }
1139
1291
 
1140
1292
  /*
@@ -1163,6 +1315,32 @@ static VALUE ruby_curl_easy_connect_timeout_get(VALUE self, VALUE connect_timeou
1163
1315
  CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
1164
1316
  }
1165
1317
 
1318
+ /*
1319
+ * call-seq:
1320
+ * easy.connect_timeout_ms = fixnum or nil => fixnum or nil
1321
+ *
1322
+ * Set the maximum time in milliseconds that you allow the connection to the
1323
+ * server to take. This only limits the connection phase, once it has
1324
+ * connected, this option is of no more use.
1325
+ *
1326
+ * Set to nil (or zero) to disable connection timeout (it will then only
1327
+ * timeout on the system's internal timeouts).
1328
+ */
1329
+ static VALUE ruby_curl_easy_connect_timeout_ms_set(VALUE self, VALUE connect_timeout_ms) {
1330
+ CURB_IMMED_SETTER(ruby_curl_easy, connect_timeout_ms, 0);
1331
+ }
1332
+
1333
+ /*
1334
+ * call-seq:
1335
+ * easy.connect_timeout_ms => fixnum or nil
1336
+ *
1337
+ * Obtain the maximum time in milliseconds that you allow the connection to the
1338
+ * server to take.
1339
+ */
1340
+ static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self, VALUE connect_timeout_ms) {
1341
+ CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout_ms, 0);
1342
+ }
1343
+
1166
1344
  /*
1167
1345
  * call-seq:
1168
1346
  * easy.dns_cache_timeout = fixnum or nil => fixnum or nil
@@ -1258,6 +1436,46 @@ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time)
1258
1436
  CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
1259
1437
  }
1260
1438
 
1439
+ /*
1440
+ * call-seq:
1441
+ * easy.max_send_speed_large = fixnum or nil => fixnum or nil
1442
+ *
1443
+ * Set the maximal sending transfer speed (in bytes per second)
1444
+ */
1445
+ static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_speed_large) {
1446
+ CURB_IMMED_SETTER(ruby_curl_easy, max_send_speed_large, 0);
1447
+ }
1448
+
1449
+ /*
1450
+ * call-seq:
1451
+ * easy.max_send_speed_large = fixnum or nil => fixnum or nil
1452
+ *
1453
+ * Get the maximal sending transfer speed (in bytes per second)
1454
+ */
1455
+ static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self, VALUE max_send_speed_large) {
1456
+ CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
1457
+ }
1458
+
1459
+ /*
1460
+ * call-seq:
1461
+ * easy.max_recv_speed_large = fixnum or nil => fixnum or nil
1462
+ *
1463
+ * Set the maximal receiving transfer speed (in bytes per second)
1464
+ */
1465
+ static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_speed_large) {
1466
+ CURB_IMMED_SETTER(ruby_curl_easy, max_recv_speed_large, 0);
1467
+ }
1468
+
1469
+ /*
1470
+ * call-seq:
1471
+ * easy.max_recv_speed_large = fixnum or nil => fixnum or nil
1472
+ *
1473
+ * Get the maximal receiving transfer speed (in bytes per second)
1474
+ */
1475
+ static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self, VALUE max_recv_speed_large) {
1476
+ CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
1477
+ }
1478
+
1261
1479
  /*
1262
1480
  * call-seq:
1263
1481
  * easy.username = string => string
@@ -1275,7 +1493,7 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
1275
1493
  /*
1276
1494
  * call-seq:
1277
1495
  * easy.username => string
1278
- *
1496
+ *
1279
1497
  * Get the current username
1280
1498
  */
1281
1499
  static VALUE ruby_curl_easy_username_get(VALUE self, VALUE username) {
@@ -1303,7 +1521,7 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
1303
1521
  /*
1304
1522
  * call-seq:
1305
1523
  * easy.password => string
1306
- *
1524
+ *
1307
1525
  * Get the current password
1308
1526
  */
1309
1527
  static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
@@ -1319,8 +1537,16 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
1319
1537
  * easy.ssl_version = value => fixnum or nil
1320
1538
  *
1321
1539
  * Sets the version of SSL/TLS that libcurl will attempt to use. Valid
1322
- * options are Curl::CURL_SSLVERSION_TLSv1, Curl::CURL_SSLVERSION::SSLv2,
1323
- * Curl::CURL_SSLVERSION_SSLv3 and Curl::CURL_SSLVERSION_DEFAULT
1540
+ * options are:
1541
+ *
1542
+ * Curl::CURL_SSLVERSION_DEFAULT
1543
+ * Curl::CURL_SSLVERSION_TLSv1 (TLS 1.x)
1544
+ * Curl::CURL_SSLVERSION_SSLv2
1545
+ * Curl::CURL_SSLVERSION_SSLv3
1546
+ * Curl::CURL_SSLVERSION_TLSv1_0
1547
+ * Curl::CURL_SSLVERSION_TLSv1_1
1548
+ * Curl::CURL_SSLVERSION_TLSv1_2
1549
+ * Curl::CURL_SSLVERSION_TLSv1_3
1324
1550
  */
1325
1551
  static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
1326
1552
  CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
@@ -1339,7 +1565,7 @@ static VALUE ruby_curl_easy_ssl_version_get(VALUE self, VALUE ssl_version) {
1339
1565
  /*
1340
1566
  * call-seq:
1341
1567
  * easy.use_ssl = value => fixnum or nil
1342
- *
1568
+ *
1343
1569
  * Ensure libcurl uses SSL for FTP connections. Valid options are Curl::CURL_USESSL_NONE,
1344
1570
  * Curl::CURL_USESSL_TRY, Curl::CURL_USESSL_CONTROL, and Curl::CURL_USESSL_ALL.
1345
1571
  */
@@ -1453,7 +1679,7 @@ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1453
1679
 
1454
1680
  /*
1455
1681
  * call-seq:
1456
- * easy.ssl_verify_host = boolean => boolean
1682
+ * easy.ssl_verify_host = [0, 1, 2] => [0, 1, 2]
1457
1683
  *
1458
1684
  * Configure whether this Curl instance will verify that the server cert
1459
1685
  * is for the server it is known as. When true (the default) the server
@@ -1465,18 +1691,18 @@ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1465
1691
  * The server could be lying. To control lying, see ssl_verify_peer? .
1466
1692
  */
1467
1693
  static VALUE ruby_curl_easy_ssl_verify_host_set(VALUE self, VALUE ssl_verify_host) {
1468
- CURB_BOOLEAN_SETTER(ruby_curl_easy, ssl_verify_host);
1694
+ CURB_IMMED_SETTER(ruby_curl_easy, ssl_verify_host, 0);
1469
1695
  }
1470
1696
 
1471
1697
  /*
1472
1698
  * call-seq:
1473
- * easy.ssl_verify_host? => boolean
1699
+ * easy.ssl_verify_host => number
1474
1700
  *
1475
1701
  * Determine whether this Curl instance will verify that the server cert
1476
1702
  * is for the server it is known as.
1477
1703
  */
1478
- static VALUE ruby_curl_easy_ssl_verify_host_q(VALUE self) {
1479
- CURB_BOOLEAN_GETTER(ruby_curl_easy, ssl_verify_host);
1704
+ static VALUE ruby_curl_easy_ssl_verify_host_get(VALUE self) {
1705
+ CURB_IMMED_GETTER(ruby_curl_easy, ssl_verify_host, 0);
1480
1706
  }
1481
1707
 
1482
1708
  /*
@@ -1524,17 +1750,6 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
1524
1750
  CURB_BOOLEAN_GETTER(ruby_curl_easy, use_netrc);
1525
1751
  }
1526
1752
 
1527
- /*
1528
- * call-seq:
1529
- * easy.follow_location = boolean => boolean
1530
- *
1531
- * Configure whether this Curl instance will follow Location: headers
1532
- * in HTTP responses. Redirects will only be followed to the extent
1533
- * specified by +max_redirects+.
1534
- */
1535
- static VALUE ruby_curl_easy_follow_location_set(VALUE self, VALUE follow_location) {
1536
- CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
1537
- }
1538
1753
  /*
1539
1754
  * call-seq:
1540
1755
  *
@@ -1685,19 +1900,80 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
1685
1900
  CURB_BOOLEAN_GETTER(ruby_curl_easy, ignore_content_length);
1686
1901
  }
1687
1902
 
1903
+ /*
1904
+ * call-seq:
1905
+ * easy.resolve_mode => symbol
1906
+ *
1907
+ * Determines what type of IP address this Curl::Easy instance
1908
+ * resolves DNS names to.
1909
+ */
1910
+ static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
1911
+ ruby_curl_easy *rbce;
1912
+ unsigned short rm;
1913
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1688
1914
 
1915
+ rm = rbce->resolve_mode;
1689
1916
 
1690
- /* ================= EVENT PROCS ================== */
1917
+ switch(rm) {
1918
+ case CURL_IPRESOLVE_V4:
1919
+ return rb_easy_sym("ipv4");
1920
+ case CURL_IPRESOLVE_V6:
1921
+ return rb_easy_sym("ipv6");
1922
+ default:
1923
+ return rb_easy_sym("auto");
1924
+ }
1925
+ }
1691
1926
 
1692
1927
  /*
1693
1928
  * call-seq:
1694
- * easy.on_body { |body_data| ... } => &lt;old handler&gt;
1929
+ * easy.resolve_mode = symbol => symbol
1695
1930
  *
1696
- * Assign or remove the +on_body+ handler for this Curl::Easy instance.
1697
- * To remove a previously-supplied handler, call this method with no
1698
- * attached block.
1931
+ * Configures what type of IP address this Curl::Easy instance
1932
+ * resolves DNS names to. Valid options are:
1699
1933
  *
1700
- * The +on_body+ handler is called for each chunk of response body passed back
1934
+ * [:auto] resolves DNS names to all IP versions your system allows
1935
+ * [:ipv4] resolves DNS names to IPv4 only
1936
+ * [:ipv6] resolves DNS names to IPv6 only
1937
+ */
1938
+ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
1939
+ if (TYPE(resolve_mode) != T_SYMBOL) {
1940
+ rb_raise(rb_eTypeError, "Must pass a symbol");
1941
+ return Qnil;
1942
+ } else {
1943
+ ruby_curl_easy *rbce;
1944
+ ID resolve_mode_id;
1945
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1946
+
1947
+ resolve_mode_id = rb_to_id(resolve_mode);
1948
+
1949
+ if (resolve_mode_id == rb_intern("auto")) {
1950
+ rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
1951
+ return resolve_mode;
1952
+ } else if (resolve_mode_id == rb_intern("ipv4")) {
1953
+ rbce->resolve_mode = CURL_IPRESOLVE_V4;
1954
+ return resolve_mode;
1955
+ } else if (resolve_mode_id == rb_intern("ipv6")) {
1956
+ rbce->resolve_mode = CURL_IPRESOLVE_V6;
1957
+ return resolve_mode;
1958
+ } else {
1959
+ rb_raise(rb_eArgError, "Must set to one of :auto, :ipv4, :ipv6");
1960
+ return Qnil;
1961
+ }
1962
+ }
1963
+ }
1964
+
1965
+
1966
+ /* ================= EVENT PROCS ================== */
1967
+
1968
+ /*
1969
+ * call-seq:
1970
+ * easy.on_body { |body_data| ... } => &lt;old handler&gt;
1971
+ *
1972
+ * Assign or remove the +on_body+ handler for this Curl::Easy instance.
1973
+ * To remove a previously-supplied handler, call this method with no
1974
+ * attached block.
1975
+ *
1976
+ * The +on_body+ handler is called for each chunk of response body passed back
1701
1977
  * by libcurl during +perform+. It should perform any processing necessary,
1702
1978
  * and return the actual number of bytes handled. Normally, this will
1703
1979
  * equal the length of the data string, and CURL will continue processing.
@@ -1738,6 +2014,36 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
1738
2014
  CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, failure_proc);
1739
2015
  }
1740
2016
 
2017
+ /*
2018
+ * call-seq:
2019
+ * easy.on_missing {|easy,code| ... } => &lt;old handler;&gt;
2020
+ *
2021
+ * Assign or remove the on_missing handler for this Curl::Easy instance.
2022
+ * To remove a previously-supplied handler, call this method with no attached
2023
+ * block.
2024
+ *
2025
+ * The +on_missing+ handler is called when request is finished with a
2026
+ * status of 40x
2027
+ */
2028
+ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
2029
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, missing_proc);
2030
+ }
2031
+
2032
+ /*
2033
+ * call-seq:
2034
+ * easy.on_redirect {|easy,code| ... } => &lt;old handler;&gt;
2035
+ *
2036
+ * Assign or remove the on_redirect handler for this Curl::Easy instance.
2037
+ * To remove a previously-supplied handler, call this method with no attached
2038
+ * block.
2039
+ *
2040
+ * The +on_redirect+ handler is called when request is finished with a
2041
+ * status of 30x
2042
+ */
2043
+ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
2044
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, redirect_proc);
2045
+ }
2046
+
1741
2047
  /*
1742
2048
  * call-seq:
1743
2049
  * easy.on_complete {|easy| ... } => &lt;old handler&gt;
@@ -1816,9 +2122,12 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
1816
2122
  /***********************************************
1817
2123
  * This is an rb_iterate callback used to set up http headers.
1818
2124
  */
1819
- static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
2125
+ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
2126
+ struct curl_slist **list;
1820
2127
  VALUE header_str = Qnil;
1821
2128
 
2129
+ Data_Get_Struct(wrap, struct curl_slist *, list);
2130
+
1822
2131
  //rb_p(header);
1823
2132
 
1824
2133
  if (rb_type(header) == T_ARRAY) {
@@ -1842,28 +2151,80 @@ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1842
2151
  return header_str;
1843
2152
  }
1844
2153
 
2154
+ /***********************************************
2155
+ * This is an rb_iterate callback used to set up http proxy headers.
2156
+ */
2157
+ static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap) {
2158
+ struct curl_slist **list;
2159
+ VALUE proxy_header_str = Qnil;
2160
+
2161
+ Data_Get_Struct(wrap, struct curl_slist *, list);
2162
+
2163
+ //rb_p(proxy_header);
2164
+
2165
+ if (rb_type(proxy_header) == T_ARRAY) {
2166
+ // we're processing a hash, proxy header is [name, val]
2167
+ VALUE name, value;
2168
+
2169
+ name = rb_obj_as_string(rb_ary_entry(proxy_header, 0));
2170
+ value = rb_obj_as_string(rb_ary_entry(proxy_header, 1));
2171
+
2172
+ // This is a bit inefficient, but we don't want to be modifying
2173
+ // the actual values in the original hash.
2174
+ proxy_header_str = rb_str_plus(name, rb_str_new2(": "));
2175
+ proxy_header_str = rb_str_plus(proxy_header_str, value);
2176
+ } else {
2177
+ proxy_header_str = rb_obj_as_string(proxy_header);
2178
+ }
2179
+
2180
+ //rb_p(header_str);
2181
+
2182
+ *list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
2183
+ return proxy_header_str;
2184
+ }
2185
+
1845
2186
  /***********************************************
1846
2187
  * This is an rb_iterate callback used to set up ftp commands.
1847
2188
  */
1848
- static VALUE cb_each_ftp_command(VALUE ftp_command, struct curl_slist **list) {
1849
- VALUE ftp_command_string = rb_obj_as_string(ftp_command);
2189
+ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
2190
+ struct curl_slist **list;
2191
+ VALUE ftp_command_string;
2192
+ Data_Get_Struct(wrap, struct curl_slist *, list);
2193
+
2194
+ ftp_command_string = rb_obj_as_string(ftp_command);
1850
2195
  *list = curl_slist_append(*list, StringValuePtr(ftp_command));
1851
2196
 
1852
2197
  return ftp_command_string;
1853
2198
  }
1854
2199
 
2200
+ /***********************************************
2201
+ * This is an rb_iterate callback used to set up the resolve list.
2202
+ */
2203
+ static VALUE cb_each_resolve(VALUE resolve, VALUE wrap) {
2204
+ struct curl_slist **list;
2205
+ VALUE resolve_string;
2206
+ Data_Get_Struct(wrap, struct curl_slist *, list);
2207
+
2208
+ resolve_string = rb_obj_as_string(resolve);
2209
+ *list = curl_slist_append(*list, StringValuePtr(resolve));
2210
+
2211
+ return resolve_string;
2212
+ }
2213
+
1855
2214
  /***********************************************
1856
2215
  *
1857
2216
  * Setup a connection
1858
2217
  *
1859
2218
  * Always returns Qtrue, rb_raise on error.
1860
2219
  */
1861
- VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2220
+ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
1862
2221
  // TODO this could do with a bit of refactoring...
1863
2222
  CURL *curl;
1864
2223
  VALUE url, _url = rb_easy_get("url");
1865
2224
  struct curl_slist **hdrs = &(rbce->curl_headers);
2225
+ struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
1866
2226
  struct curl_slist **cmds = &(rbce->curl_ftp_commands);
2227
+ struct curl_slist **rslv = &(rbce->curl_resolve);
1867
2228
 
1868
2229
  curl = rbce->curl;
1869
2230
 
@@ -1872,8 +2233,6 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1872
2233
  }
1873
2234
 
1874
2235
  url = rb_check_string_type(_url);
1875
-
1876
- // Need to configure the handler as per settings in rbce
1877
2236
  curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
1878
2237
 
1879
2238
  // network stuff and auth
@@ -1921,8 +2280,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1921
2280
 
1922
2281
  // body/header procs
1923
2282
  if (!rb_easy_nil("body_proc")) {
1924
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler);
1925
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, rb_easy_get("body_proc"));//rbce->body_proc);
2283
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
2284
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
1926
2285
  /* clear out the body_data if it was set */
1927
2286
  rb_easy_del("body_data");
1928
2287
  } else {
@@ -1932,8 +2291,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1932
2291
  }
1933
2292
 
1934
2293
  if (!rb_easy_nil("header_proc")) {
1935
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler);
1936
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, rb_easy_get("header_proc"));
2294
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler_header);
2295
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
1937
2296
  /* clear out the header_data if it was set */
1938
2297
  rb_easy_del("header_data");
1939
2298
  } else {
@@ -1976,22 +2335,30 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1976
2335
  curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
1977
2336
  curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
1978
2337
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
1979
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_peer);
2338
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_host);
1980
2339
 
1981
2340
  if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
1982
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_OPTIONAL);
2341
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1983
2342
  } else {
1984
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_IGNORED);
2343
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
1985
2344
  }
1986
2345
 
1987
2346
  curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
1988
2347
 
1989
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, rbce->timeout);
2348
+ #if HAVE_CURLOPT_TIMEOUT_MS
2349
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
2350
+ #endif
2351
+
1990
2352
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
2353
+ #if HAVE_CURLOPT_CONNECTTIMEOUT_MS
2354
+ curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, rbce->connect_timeout_ms);
2355
+ #endif
1991
2356
  curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
1992
2357
 
1993
2358
  curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
1994
2359
 
2360
+ curl_easy_setopt(curl, CURLOPT_IPRESOLVE, rbce->resolve_mode);
2361
+
1995
2362
 
1996
2363
  #if LIBCURL_VERSION_NUM >= 0x070a08
1997
2364
  curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
@@ -2004,6 +2371,9 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2004
2371
  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
2005
2372
  curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
2006
2373
 
2374
+ curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, rbce->max_recv_speed_large);
2375
+ curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, rbce->max_send_speed_large);
2376
+
2007
2377
  // Set up localport / proxy port
2008
2378
  // FIXME these won't get returned to default if they're unset Ruby
2009
2379
  if (rbce->proxy_port > 0) {
@@ -2036,21 +2406,20 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2036
2406
  #endif
2037
2407
  }
2038
2408
 
2039
- if (rbce->http_auth_types > 0) {
2409
+ /*
2410
+ * NOTE: we used to set CURLAUTH_ANY but see: http://curl.haxx.se/mail/lib-2015-06/0033.html
2411
+ */
2412
+ if (rbce->http_auth_types != 0) {
2040
2413
  #if LIBCURL_VERSION_NUM >= 0x070a06
2041
2414
  curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
2042
- } else {
2043
- curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
2044
2415
  #else
2045
2416
  rb_warn("Installed libcurl is too old to support http_auth_types");
2046
2417
  #endif
2047
2418
  }
2048
2419
 
2049
- if (rbce->proxy_auth_types > 0) {
2420
+ if (rbce->proxy_auth_types != 0) {
2050
2421
  #if LIBCURL_VERSION_NUM >= 0x070a07
2051
2422
  curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
2052
- } else {
2053
- curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
2054
2423
  #else
2055
2424
  rb_warn("Installed libcurl is too old to support proxy_auth_types");
2056
2425
  #endif
@@ -2077,7 +2446,9 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2077
2446
 
2078
2447
  /* Set up HTTPS cert handling if necessary */
2079
2448
  if (!rb_easy_nil("cert")) {
2080
- curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2449
+ if (!rb_easy_nil("certtype")) {
2450
+ curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2451
+ }
2081
2452
  curl_easy_setopt(curl, CURLOPT_SSLCERT, rb_easy_get_str("cert"));
2082
2453
  if (!rb_easy_nil("certpassword")) {
2083
2454
  curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, rb_easy_get_str("certpassword"));
@@ -2086,13 +2457,15 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2086
2457
  curl_easy_setopt(curl, CURLOPT_SSLKEY, rb_easy_get_str("cert_key"));
2087
2458
  }
2088
2459
  }
2460
+
2089
2461
  if (!rb_easy_nil("cacert")) {
2462
+ curl_easy_setopt(curl, CURLOPT_CAINFO, rb_easy_get_str("cacert"));
2463
+ }
2090
2464
  #ifdef HAVE_CURL_CONFIG_CA
2465
+ else {
2091
2466
  curl_easy_setopt(curl, CURLOPT_CAINFO, CURL_CONFIG_CA);
2092
- #else
2093
- curl_easy_setopt(curl, CURLOPT_CAINFO, "/usr/local/share/curl/curl-ca-bundle.crt");
2094
- #endif
2095
2467
  }
2468
+ #endif
2096
2469
 
2097
2470
  #ifdef CURL_VERSION_SSL
2098
2471
  if (rbce->ssl_version > 0) {
@@ -2107,7 +2480,7 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2107
2480
  rb_warn("libcurl is not configured with SSL support");
2108
2481
  }
2109
2482
  #endif
2110
-
2483
+
2111
2484
  if (rbce->ftp_filemethod > 0) {
2112
2485
  curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
2113
2486
  }
@@ -2122,7 +2495,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2122
2495
 
2123
2496
  if (!rb_easy_nil("headers")) {
2124
2497
  if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_HASH)) {
2125
- rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, (VALUE)hdrs);
2498
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, hdrs);
2499
+ rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, wrap);
2126
2500
  } else {
2127
2501
  VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
2128
2502
  *hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
@@ -2133,10 +2507,30 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2133
2507
  }
2134
2508
  }
2135
2509
 
2510
+ #if HAVE_CURLOPT_PROXYHEADER
2511
+ /* Setup HTTP proxy headers if necessary */
2512
+ curl_easy_setopt(curl, CURLOPT_PROXYHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
2513
+
2514
+ if (!rb_easy_nil("proxy_headers")) {
2515
+ if (rb_easy_type_check("proxy_headers", T_ARRAY) || rb_easy_type_check("proxy_headers", T_HASH)) {
2516
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, phdrs);
2517
+ rb_iterate(rb_each, rb_easy_get("proxy_headers"), cb_each_http_proxy_header, wrap);
2518
+ } else {
2519
+ VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
2520
+ *phdrs = curl_slist_append(*hdrs, StringValuePtr(proxy_headers_str));
2521
+ }
2522
+
2523
+ if (*phdrs) {
2524
+ curl_easy_setopt(curl, CURLOPT_PROXYHEADER, *phdrs);
2525
+ }
2526
+ }
2527
+ #endif
2528
+
2136
2529
  /* Setup FTP commands if necessary */
2137
2530
  if (!rb_easy_nil("ftp_commands")) {
2138
2531
  if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
2139
- rb_iterate(rb_each, rb_easy_get("ftp_commands"), cb_each_ftp_command, (VALUE)cmds);
2532
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, cmds);
2533
+ rb_iterate(rb_each, rb_easy_get("ftp_commands"), cb_each_ftp_command, wrap);
2140
2534
  }
2141
2535
 
2142
2536
  if (*cmds) {
@@ -2144,18 +2538,33 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2144
2538
  }
2145
2539
  }
2146
2540
 
2541
+ #if HAVE_CURLOPT_RESOLVE
2542
+ /* Setup resolve list if necessary */
2543
+ if (!rb_easy_nil("resolve")) {
2544
+ if (rb_easy_type_check("resolve", T_ARRAY)) {
2545
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, rslv);
2546
+ rb_iterate(rb_each, rb_easy_get("resolve"), cb_each_resolve, wrap);
2547
+ }
2548
+
2549
+ if (*rslv) {
2550
+ curl_easy_setopt(curl, CURLOPT_RESOLVE, *rslv);
2551
+ }
2552
+ }
2553
+ #endif
2554
+
2147
2555
  return Qnil;
2148
2556
  }
2149
2557
  /***********************************************
2150
2558
  *
2151
2559
  * Clean up a connection
2152
2560
  *
2153
- * Always returns Qtrue.
2561
+ * Always returns Qnil.
2154
2562
  */
2155
2563
  VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2156
2564
 
2157
2565
  CURL *curl = rbce->curl;
2158
2566
  struct curl_slist *ftp_commands;
2567
+ struct curl_slist *resolve;
2159
2568
 
2160
2569
  /* Free everything up */
2161
2570
  if (rbce->curl_headers) {
@@ -2163,12 +2572,23 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2163
2572
  rbce->curl_headers = NULL;
2164
2573
  }
2165
2574
 
2575
+ if (rbce->curl_proxy_headers) {
2576
+ curl_slist_free_all(rbce->curl_proxy_headers);
2577
+ rbce->curl_proxy_headers = NULL;
2578
+ }
2579
+
2166
2580
  ftp_commands = rbce->curl_ftp_commands;
2167
2581
  if (ftp_commands) {
2168
2582
  curl_slist_free_all(ftp_commands);
2169
2583
  rbce->curl_ftp_commands = NULL;
2170
2584
  }
2171
2585
 
2586
+ resolve = rbce->curl_resolve;
2587
+ if (resolve) {
2588
+ curl_slist_free_all(resolve);
2589
+ rbce->curl_resolve = NULL;
2590
+ }
2591
+
2172
2592
  /* clean up a PUT request's curl options. */
2173
2593
  if (!rb_easy_nil("upload")) {
2174
2594
  rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
@@ -2178,57 +2598,10 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2178
2598
  curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
2179
2599
  }
2180
2600
 
2181
- return Qnil;
2182
- }
2183
-
2184
- /***********************************************
2185
- *
2186
- * This is the main worker for the perform methods (get, post, head, put).
2187
- * It's not surfaced as a Ruby method - instead, the individual request
2188
- * methods are responsible for setting up stuff specific to that type,
2189
- * then calling this to handle common stuff and do the perform.
2190
- *
2191
- * Always returns Qtrue, rb_raise on error.
2192
- *
2193
- */
2194
- static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {
2195
-
2196
- VALUE ret;
2197
-
2198
- /* reuse existing multi handle for this easy handle */
2199
- if (NIL_P(rbce->multi)) {
2200
- rbce->multi = ruby_curl_multi_new(cCurlMulti);
2201
- }
2202
- rb_funcall(rbce->multi, rb_intern("add"), 1, self );
2203
- ret = rb_funcall(rbce->multi, rb_intern("perform"), 0);
2204
-
2205
- /* check for errors in the easy response and raise exceptions if anything went wrong and their is no on_failure handler */
2206
- if (rbce->last_result != 0 && rb_easy_nil("failure_proc")) {
2207
- raise_curl_easy_error_exception(rbce->last_result);
2208
- }
2209
-
2210
- return ret;
2211
- }
2212
-
2213
- /*
2214
- * call-seq:
2215
- * easy.http_get => true
2216
- *
2217
- * GET the currently configured URL using the current options set for
2218
- * this Curl::Easy instance. This method always returns true, or raises
2219
- * an exception (defined under Curl::Err) on error.
2220
- */
2221
- static VALUE ruby_curl_easy_perform_get(VALUE self) {
2222
- ruby_curl_easy *rbce;
2223
- CURL *curl;
2224
-
2225
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2226
- curl = rbce->curl;
2227
-
2228
- curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2229
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
2601
+ // set values on cleanup to nil
2602
+ rb_easy_del("multi");
2230
2603
 
2231
- return handle_perform(self,rbce);
2604
+ return Qnil;
2232
2605
  }
2233
2606
 
2234
2607
  /*
@@ -2242,27 +2615,17 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
2242
2615
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2243
2616
  curl = rbce->curl;
2244
2617
 
2618
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
2619
+
2245
2620
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
2246
2621
 
2247
- retval = handle_perform(self,rbce);
2622
+ retval = rb_funcall(self, rb_intern("perform"), 0);
2248
2623
 
2249
2624
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2250
2625
 
2251
2626
  return retval;
2252
2627
  }
2253
2628
 
2254
- /*
2255
- * call-seq:
2256
- * easy.http_delete
2257
- *
2258
- * DELETE the currently configured URL using the current options set for
2259
- * this Curl::Easy instance. This method always returns true, or raises
2260
- * an exception (defined under Curl::Err) on error.
2261
- */
2262
- static VALUE ruby_curl_easy_perform_delete(VALUE self) {
2263
- return ruby_curl_easy_perform_verb_str(self, "DELETE");
2264
- }
2265
-
2266
2629
  /*
2267
2630
  * call-seq:
2268
2631
  * easy.http(verb)
@@ -2273,33 +2636,17 @@ static VALUE ruby_curl_easy_perform_delete(VALUE self) {
2273
2636
  static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
2274
2637
  VALUE str_verb;
2275
2638
  if (rb_type(verb) == T_STRING) {
2276
- return ruby_curl_easy_perform_verb_str(self, RSTRING_PTR(verb));
2639
+ return ruby_curl_easy_perform_verb_str(self, StringValueCStr(verb));
2277
2640
  }
2278
2641
  else if (rb_respond_to(verb,rb_intern("to_s"))) {
2279
2642
  str_verb = rb_funcall(verb, rb_intern("to_s"), 0);
2280
- return ruby_curl_easy_perform_verb_str(self, RSTRING_PTR(str_verb));
2643
+ return ruby_curl_easy_perform_verb_str(self, StringValueCStr(str_verb));
2281
2644
  }
2282
2645
  else {
2283
2646
  rb_raise(rb_eRuntimeError, "Invalid HTTP VERB, must response to 'to_s'");
2284
2647
  }
2285
2648
  }
2286
2649
 
2287
- /*
2288
- * call-seq:
2289
- * easy.perform => true
2290
- *
2291
- * Transfer the currently configured URL using the options set for this
2292
- * Curl::Easy instance. If this is an HTTP URL, it will be transferred via
2293
- * the GET or HEAD request method.
2294
- */
2295
- static VALUE ruby_curl_easy_perform(VALUE self) {
2296
- ruby_curl_easy *rbce;
2297
-
2298
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2299
-
2300
- return handle_perform(self,rbce);
2301
- }
2302
-
2303
2650
  /*
2304
2651
  * call-seq:
2305
2652
  * easy.http_post("url=encoded%20form%20data;and=so%20on") => true
@@ -2335,6 +2682,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2335
2682
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2336
2683
  curl = rbce->curl;
2337
2684
 
2685
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
2686
+
2338
2687
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2339
2688
 
2340
2689
  if (rbce->multipart_form_post) {
@@ -2345,6 +2694,17 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2345
2694
  for (i = 0; i < argc; i++) {
2346
2695
  if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
2347
2696
  append_to_form(argv[i], &first, &last);
2697
+ } else if (rb_type(argv[i]) == T_ARRAY) {
2698
+ // see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
2699
+ long c = 0, argv_len = RARRAY_LEN(argv[i]);
2700
+ for (; c < argv_len; ++c) {
2701
+ if (rb_obj_is_instance_of(rb_ary_entry(argv[i],c), cCurlPostField)) {
2702
+ append_to_form(rb_ary_entry(argv[i],c), &first, &last);
2703
+ } else {
2704
+ rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
2705
+ return Qnil;
2706
+ }
2707
+ }
2348
2708
  } else {
2349
2709
  rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
2350
2710
  return Qnil;
@@ -2353,7 +2713,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2353
2713
 
2354
2714
  curl_easy_setopt(curl, CURLOPT_POST, 0);
2355
2715
  curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
2356
- ret = handle_perform(self,rbce);
2716
+ ret = rb_funcall(self, rb_intern("perform"), 0);
2357
2717
  curl_formfree(first);
2358
2718
 
2359
2719
  return ret;
@@ -2375,114 +2735,11 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2375
2735
  ruby_curl_easy_post_body_set(self, post_body);
2376
2736
  }
2377
2737
 
2378
- return handle_perform(self,rbce);
2738
+ return rb_funcall(self, rb_intern("perform"), 0);
2379
2739
  }
2380
2740
  }
2381
2741
  }
2382
2742
 
2383
- /*
2384
- * call-seq:
2385
- * easy.http_head => true
2386
- *
2387
- * Request headers from the currently configured URL using the HEAD
2388
- * method and current options set for this Curl::Easy instance. This
2389
- * method always returns true, or raises an exception (defined under
2390
- * Curl::Err) on error.
2391
- *
2392
- */
2393
- static VALUE ruby_curl_easy_perform_head(VALUE self) {
2394
- ruby_curl_easy *rbce;
2395
- CURL *curl;
2396
- VALUE ret;
2397
-
2398
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2399
- curl = rbce->curl;
2400
-
2401
- curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
2402
-
2403
- ret = handle_perform(self,rbce);
2404
-
2405
- curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
2406
- return ret;
2407
- }
2408
-
2409
- /*
2410
- *call-seq:
2411
- * easy = Curl::Easy.new("url") do|c|
2412
- * c.head = true
2413
- * end
2414
- * easy.perform
2415
- */
2416
- static VALUE ruby_curl_easy_set_head_option(VALUE self, VALUE onoff) {
2417
- ruby_curl_easy *rbce;
2418
-
2419
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2420
-
2421
- if( onoff == Qtrue ) {
2422
- curl_easy_setopt(rbce->curl, CURLOPT_NOBODY, 1);
2423
- }
2424
- else {
2425
- curl_easy_setopt(rbce->curl, CURLOPT_NOBODY, 0);
2426
- }
2427
-
2428
- return onoff;
2429
- }
2430
- /*
2431
- *call-seq:
2432
- *
2433
- * easy = Curl::Easy.new("url")
2434
- * easy.version = Curl::HTTP_1_1
2435
- * easy.version = Curl::HTTP_1_0
2436
- * easy.version = Curl::HTTP_NONE
2437
- *
2438
- */
2439
- static VALUE ruby_curl_easy_set_version(VALUE self, VALUE version) {
2440
- ruby_curl_easy *rbce;
2441
- //fprintf(stderr,"CURL_HTTP_VERSION_1_1: %d, CURL_HTTP_VERSION_1_0: %d, CURL_HTTP_VERSION_NONE: %d\n", CURL_HTTP_VERSION_1_1, CURL_HTTP_VERSION_1_0, CURL_HTTP_VERSION_NONE);
2442
-
2443
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2444
-
2445
- curl_easy_setopt(rbce->curl, CURLOPT_HTTP_VERSION, FIX2INT(version));
2446
-
2447
- return version;
2448
- }
2449
- /*
2450
- * call-seq:
2451
- *
2452
- * easy = Curl::Easy.new
2453
- * easy.nosignal = true
2454
- */
2455
- static VALUE ruby_curl_easy_set_nosignal(VALUE self, VALUE onoff) {
2456
- ruby_curl_easy *rbce;
2457
-
2458
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2459
-
2460
- curl_easy_setopt(rbce->curl, CURLOPT_NOSIGNAL, (Qtrue == onoff) ? 1 : 0);
2461
-
2462
- return onoff;
2463
- }
2464
- /*
2465
- *call-seq:
2466
- * easy = Curl::Easy.new("url") do|c|
2467
- * c.delete = true
2468
- * end
2469
- * easy.perform
2470
- */
2471
- static VALUE ruby_curl_easy_set_delete_option(VALUE self, VALUE onoff) {
2472
- ruby_curl_easy *rbce;
2473
-
2474
- Data_Get_Struct(self, ruby_curl_easy, rbce);
2475
-
2476
- if( onoff == Qtrue ) {
2477
- curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, "DELETE");
2478
- }
2479
- else {
2480
- curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NULL);
2481
- }
2482
-
2483
- return onoff;
2484
- }
2485
-
2486
2743
  /*
2487
2744
  * call-seq:
2488
2745
  * easy.http_put(data) => true
@@ -2494,28 +2751,19 @@ static VALUE ruby_curl_easy_set_delete_option(VALUE self, VALUE onoff) {
2494
2751
  static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
2495
2752
  ruby_curl_easy *rbce;
2496
2753
  CURL *curl;
2497
-
2754
+
2498
2755
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2499
2756
  curl = rbce->curl;
2500
-
2757
+
2758
+ memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
2759
+
2501
2760
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2502
2761
  ruby_curl_easy_put_data_set(self, data);
2503
-
2504
- return handle_perform(self, rbce);
2505
- }
2506
2762
 
2507
- /*
2508
- * call-seq:
2509
- * Curl::Easy.http_put(url, data) {|c| ... }
2510
- *
2511
- * see easy.http_put
2512
- */
2513
- static VALUE ruby_curl_easy_class_perform_put(VALUE klass, VALUE url, VALUE data) {
2514
- VALUE c = ruby_curl_easy_new(1, &url, klass);
2515
- ruby_curl_easy_perform_put(c, data);
2516
- return c;
2763
+ return rb_funcall(self, rb_intern("perform"), 0);
2517
2764
  }
2518
2765
 
2766
+
2519
2767
  /* =================== DATA FUNCS =============== */
2520
2768
 
2521
2769
  /*
@@ -2603,7 +2851,7 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
2603
2851
  static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
2604
2852
  ruby_curl_easy *rbce;
2605
2853
  char* ip;
2606
-
2854
+
2607
2855
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2608
2856
  curl_easy_getinfo(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
2609
2857
 
@@ -2659,7 +2907,7 @@ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
2659
2907
  return LONG2NUM(time);
2660
2908
  #else
2661
2909
  rb_warn("Installed libcurl is too old to support file_time");
2662
- return INT2FIX(0);
2910
+ return LONG2NUM(0);
2663
2911
  #endif
2664
2912
  }
2665
2913
 
@@ -2714,6 +2962,29 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
2714
2962
  return rb_float_new(time);
2715
2963
  }
2716
2964
 
2965
+ /*
2966
+ * call-seq:
2967
+ * easy.app_connect_time => float
2968
+ *
2969
+ * Retrieve the time, in seconds, it took from the start until the SSL/SSH
2970
+ * connect/handshake to the remote host was completed. This time is most often
2971
+ * very near to the pre transfer time, except for cases such as HTTP
2972
+ * pipelining where the pretransfer time can be delayed due to waits in line
2973
+ * for the pipeline and more.
2974
+ */
2975
+ #if defined(HAVE_CURLINFO_APPCONNECT_TIME)
2976
+ static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
2977
+ ruby_curl_easy *rbce;
2978
+ double time;
2979
+
2980
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2981
+ curl_easy_getinfo(rbce->curl, CURLINFO_APPCONNECT_TIME, &time);
2982
+
2983
+ return rb_float_new(time);
2984
+ }
2985
+ #endif
2986
+
2987
+
2717
2988
  /*
2718
2989
  * call-seq:
2719
2990
  * easy.pre_transfer_time => float
@@ -2796,11 +3067,41 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
2796
3067
  return LONG2NUM(count);
2797
3068
  #else
2798
3069
  rb_warn("Installed libcurl is too old to support redirect_count");
2799
- return INT2FIX(-1);
3070
+ return LONG2NUM(-1);
2800
3071
  #endif
2801
3072
 
2802
3073
  }
2803
3074
 
3075
+ /*
3076
+ * call-seq:
3077
+ * easy.redirect_url => "http://some.url" or nil
3078
+ *
3079
+ * Retrieve the URL a redirect would take you to if you
3080
+ * would enable CURLOPT_FOLLOWLOCATION.
3081
+ *
3082
+ * Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
3083
+ */
3084
+ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
3085
+ #ifdef HAVE_CURLINFO_REDIRECT_URL
3086
+ ruby_curl_easy *rbce;
3087
+ char* url;
3088
+
3089
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3090
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
3091
+
3092
+ if (url && url[0]) { // curl returns empty string if none
3093
+ return rb_str_new2(url);
3094
+ } else {
3095
+ return Qnil;
3096
+ }
3097
+ #else
3098
+ rb_warn("Installed libcurl is too old to support redirect_url");
3099
+ return LONG2NUM(-1);
3100
+ #endif
3101
+ }
3102
+
3103
+
3104
+
2804
3105
  /*
2805
3106
  * call-seq:
2806
3107
  * easy.uploaded_bytes => float
@@ -2923,7 +3224,10 @@ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
2923
3224
 
2924
3225
  /* TODO CURLINFO_SSL_ENGINES
2925
3226
 
2926
- Pass the address of a 'struct curl_slist *' to receive a linked-list of OpenSSL crypto-engines supported. Note that engines are normally implemented in separate dynamic libraries. Hence not all the returned engines may be available at run-time. NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done with it, as libcurl will not free the data for you. (Added in 7.12.3)
3227
+ Pass the address of a 'struct curl_slist *' to receive a linked-list of OpenSSL crypto-engines supported.
3228
+ Note that engines are normally implemented in separate dynamic libraries.
3229
+ Hence not all the returned engines may be available at run-time.
3230
+ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done with it, as libcurl will not free the data for you. (Added in 7.12.3)
2927
3231
  */
2928
3232
 
2929
3233
  /*
@@ -3021,7 +3325,7 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
3021
3325
  return LONG2NUM(result);
3022
3326
  #else
3023
3327
  rb_warn("Installed libcurl is too old to support os_errno");
3024
- return INT2FIX(0);
3328
+ return LONG2NUM(0);
3025
3329
  #endif
3026
3330
  }
3027
3331
 
@@ -3050,17 +3354,45 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
3050
3354
  return LONG2NUM(result);
3051
3355
  #else
3052
3356
  rb_warn("Installed libcurl is too old to support num_connects");
3053
- return INT2FIX(-1);
3357
+ return LONG2NUM(-1);
3054
3358
  #endif
3055
3359
  }
3056
3360
 
3057
3361
 
3058
- /* TODO this needs to be implemented.
3362
+ /*
3363
+ * call-seq:
3364
+ * easy.cookielist => array
3365
+ *
3366
+ * Retrieves the cookies curl knows in an array of strings.
3367
+ * Returned strings are in Netscape cookiejar format or in Set-Cookie format.
3368
+ *
3369
+ * See also option CURLINFO_COOKIELIST of curl_easy_getopt(3) to see how libcurl behaves.
3370
+ *
3371
+ * (requires libcurl 7.14.1 or higher, otherwise -1 is always returned).
3372
+ */
3373
+ static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
3374
+ #ifdef HAVE_CURLINFO_COOKIELIST
3375
+ ruby_curl_easy *rbce;
3376
+ struct curl_slist *cookies;
3377
+ struct curl_slist *cookie;
3378
+ VALUE rb_cookies;
3059
3379
 
3060
- CURLINFO_COOKIELIST
3380
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3381
+ curl_easy_getinfo(rbce->curl, CURLINFO_COOKIELIST, &cookies);
3382
+ if (!cookies)
3383
+ return Qnil;
3384
+ rb_cookies = rb_ary_new();
3385
+ for (cookie = cookies; cookie; cookie = cookie->next)
3386
+ rb_ary_push(rb_cookies, rb_str_new2(cookie->data));
3387
+ curl_slist_free_all(cookies);
3388
+ return rb_cookies;
3389
+
3390
+ #else
3391
+ rb_warn("Installed libcurl is too old to support cookielist");
3392
+ return INT2FIX(-1);
3393
+ #endif
3394
+ }
3061
3395
 
3062
- Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all cookies cURL knows (expired ones, too). Don't forget to curl_slist_free_all(3) the list after it has been used. If there are no cookies (cookies for the handle have not been enabled or simply none have been received) 'struct curl_slist *' will be set to point to NULL. (Added in 7.14.1)
3063
- */
3064
3396
 
3065
3397
  /* TODO this needs to be implemented. Could probably support CONNECT_ONLY by having this
3066
3398
  * return an open Socket or something.
@@ -3099,6 +3431,239 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
3099
3431
  #endif
3100
3432
  }
3101
3433
 
3434
+ /*
3435
+ * call-seq:
3436
+ * easy.multi => "#<Curl::Multi>"
3437
+ */
3438
+ static VALUE ruby_curl_easy_multi_get(VALUE self) {
3439
+ ruby_curl_easy *rbce;
3440
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3441
+ return rbce->multi;
3442
+ }
3443
+
3444
+ /*
3445
+ * call-seq:
3446
+ * easy.multi=multi => "#<Curl::Multi>"
3447
+ */
3448
+ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
3449
+ ruby_curl_easy *rbce;
3450
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3451
+ rbce->multi = multi;
3452
+ return rbce->multi;
3453
+ }
3454
+
3455
+ /*
3456
+ * call-seq:
3457
+ * easy.last_result => 0
3458
+ */
3459
+ static VALUE ruby_curl_easy_last_result(VALUE self) {
3460
+ ruby_curl_easy *rbce;
3461
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3462
+ return LONG2NUM(rbce->last_result);
3463
+ }
3464
+
3465
+ /*
3466
+ * call-seq:
3467
+ * easy.last_error => "Error details" or nil
3468
+ */
3469
+ static VALUE ruby_curl_easy_last_error(VALUE self) {
3470
+ ruby_curl_easy *rbce;
3471
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3472
+
3473
+ if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
3474
+ return rb_str_new2(rbce->err_buf);
3475
+ } else {
3476
+ return Qnil;
3477
+ }
3478
+ }
3479
+
3480
+ /*
3481
+ * call-seq:
3482
+ * easy.setopt Fixnum, value => value
3483
+ *
3484
+ * Initial access to libcurl curl_easy_setopt
3485
+ */
3486
+ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3487
+ ruby_curl_easy *rbce;
3488
+ long option = NUM2LONG(opt);
3489
+ rb_io_t *open_f_ptr;
3490
+
3491
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3492
+
3493
+ switch (option) {
3494
+ /* BEHAVIOR OPTIONS */
3495
+ case CURLOPT_VERBOSE: {
3496
+ VALUE verbose = val;
3497
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, verbose);
3498
+ } break;
3499
+ case CURLOPT_FOLLOWLOCATION: {
3500
+ VALUE follow_location = val;
3501
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
3502
+ } break;
3503
+ /* TODO: CALLBACK OPTIONS */
3504
+ /* TODO: ERROR OPTIONS */
3505
+ /* NETWORK OPTIONS */
3506
+ case CURLOPT_URL: {
3507
+ VALUE url = val;
3508
+ CURB_OBJECT_HSETTER(ruby_curl_easy, url);
3509
+ } break;
3510
+ case CURLOPT_CUSTOMREQUEST:
3511
+ curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NIL_P(val) ? NULL : StringValueCStr(val));
3512
+ break;
3513
+ case CURLOPT_HTTP_VERSION:
3514
+ curl_easy_setopt(rbce->curl, CURLOPT_HTTP_VERSION, NUM2LONG(val));
3515
+ break;
3516
+ case CURLOPT_PROXY: {
3517
+ VALUE proxy_url = val;
3518
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
3519
+ } break;
3520
+ case CURLOPT_INTERFACE: {
3521
+ VALUE interface_hm = val;
3522
+ CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
3523
+ } break;
3524
+ case CURLOPT_HEADER:
3525
+ case CURLOPT_NOPROGRESS:
3526
+ case CURLOPT_NOSIGNAL:
3527
+ #if HAVE_CURLOPT_PATH_AS_IS
3528
+ case CURLOPT_PATH_AS_IS:
3529
+ #endif
3530
+ #if HAVE_CURLOPT_PIPEWAIT
3531
+ case CURLOPT_PIPEWAIT:
3532
+ #endif
3533
+ case CURLOPT_HTTPGET:
3534
+ case CURLOPT_NOBODY: {
3535
+ int type = rb_type(val);
3536
+ VALUE value;
3537
+ if (type == T_TRUE) {
3538
+ value = rb_int_new(1);
3539
+ } else if (type == T_FALSE) {
3540
+ value = rb_int_new(0);
3541
+ } else {
3542
+ value = rb_funcall(val, rb_intern("to_i"), 0);
3543
+ }
3544
+ curl_easy_setopt(rbce->curl, option, NUM2LONG(value));
3545
+ } break;
3546
+ case CURLOPT_POST: {
3547
+ curl_easy_setopt(rbce->curl, CURLOPT_POST, rb_type(val) == T_TRUE);
3548
+ } break;
3549
+ case CURLOPT_MAXCONNECTS: {
3550
+ curl_easy_setopt(rbce->curl, CURLOPT_MAXCONNECTS, NUM2LONG(val));
3551
+ } break;
3552
+ case CURLOPT_POSTFIELDS: {
3553
+ curl_easy_setopt(rbce->curl, CURLOPT_POSTFIELDS, NIL_P(val) ? NULL : StringValueCStr(val));
3554
+ } break;
3555
+ case CURLOPT_USERPWD: {
3556
+ VALUE userpwd = val;
3557
+ CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
3558
+ } break;
3559
+ case CURLOPT_PROXYUSERPWD: {
3560
+ VALUE proxypwd = val;
3561
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
3562
+ } break;
3563
+ case CURLOPT_COOKIE: {
3564
+ VALUE cookies = val;
3565
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
3566
+ } break;
3567
+ case CURLOPT_COOKIEFILE: {
3568
+ VALUE cookiefile = val;
3569
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookiefile);
3570
+ } break;
3571
+ case CURLOPT_COOKIEJAR: {
3572
+ VALUE cookiejar = val;
3573
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
3574
+ } break;
3575
+ case CURLOPT_TCP_NODELAY: {
3576
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
3577
+ } break;
3578
+ case CURLOPT_RANGE: {
3579
+ curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
3580
+ } break;
3581
+ case CURLOPT_RESUME_FROM: {
3582
+ curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
3583
+ } break;
3584
+ case CURLOPT_FAILONERROR: {
3585
+ curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR, NUM2LONG(val));
3586
+ } break;
3587
+ case CURLOPT_SSL_CIPHER_LIST: {
3588
+ curl_easy_setopt(rbce->curl, CURLOPT_SSL_CIPHER_LIST, StringValueCStr(val));
3589
+ } break;
3590
+ case CURLOPT_FORBID_REUSE: {
3591
+ curl_easy_setopt(rbce->curl, CURLOPT_FORBID_REUSE, NUM2LONG(val));
3592
+ } break;
3593
+ #if HAVE_CURLOPT_GSSAPI_DELEGATION
3594
+ case CURLOPT_GSSAPI_DELEGATION: {
3595
+ curl_easy_setopt(rbce->curl, CURLOPT_GSSAPI_DELEGATION, NUM2LONG(val));
3596
+ } break;
3597
+ #endif
3598
+ #if HAVE_CURLOPT_UNIX_SOCKET_PATH
3599
+ case CURLOPT_UNIX_SOCKET_PATH: {
3600
+ curl_easy_setopt(rbce->curl, CURLOPT_UNIX_SOCKET_PATH, StringValueCStr(val));
3601
+ } break;
3602
+ #endif
3603
+ #if HAVE_CURLOPT_MAX_SEND_SPEED_LARGE
3604
+ case CURLOPT_MAX_SEND_SPEED_LARGE: {
3605
+ curl_easy_setopt(rbce->curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) NUM2LL(val));
3606
+ } break;
3607
+ #endif
3608
+ #if HAVE_CURLOPT_MAX_RECV_SPEED_LARGE
3609
+ case CURLOPT_MAX_RECV_SPEED_LARGE: {
3610
+ curl_easy_setopt(rbce->curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) NUM2LL(val));
3611
+ } break;
3612
+ #endif
3613
+ #if HAVE_CURLOPT_MAXFILESIZE
3614
+ case CURLOPT_MAXFILESIZE:
3615
+ curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
3616
+ break;
3617
+ #endif
3618
+ #if HAVE_CURLOPT_TCP_KEEPALIVE
3619
+ case CURLOPT_TCP_KEEPALIVE:
3620
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
3621
+ break;
3622
+ case CURLOPT_TCP_KEEPIDLE:
3623
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
3624
+ break;
3625
+ case CURLOPT_TCP_KEEPINTVL:
3626
+ curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
3627
+ break;
3628
+ #endif
3629
+ #if HAVE_CURLOPT_HAPROXYPROTOCOL
3630
+ case CURLOPT_HAPROXYPROTOCOL:
3631
+ curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
3632
+ break;
3633
+ #endif
3634
+ case CURLOPT_STDERR:
3635
+ // libcurl requires raw FILE pointer and this should be IO object in Ruby.
3636
+ // Tempfile or StringIO won't work.
3637
+ Check_Type(val, T_FILE);
3638
+ GetOpenFile(val, open_f_ptr);
3639
+ curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
3640
+ break;
3641
+ case CURLOPT_PROTOCOLS:
3642
+ case CURLOPT_REDIR_PROTOCOLS:
3643
+ curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
3644
+ break;
3645
+ #if HAVE_CURLOPT_SSL_SESSIONID_CACHE
3646
+ case CURLOPT_SSL_SESSIONID_CACHE:
3647
+ curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
3648
+ break;
3649
+ #endif
3650
+ default:
3651
+ rb_raise(rb_eTypeError, "Curb unsupported option");
3652
+ }
3653
+
3654
+ return val;
3655
+ }
3656
+
3657
+ /*
3658
+ * call-seq:
3659
+ * easy.getinfo Fixnum => value
3660
+ *
3661
+ * Iniital access to libcurl curl_easy_getinfo, remember getinfo doesn't return the same values as setopt
3662
+ */
3663
+ static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
3664
+ return Qnil;
3665
+ }
3666
+
3102
3667
  /*
3103
3668
  * call-seq:
3104
3669
  * easy.inspect => "#<Curl::Easy http://google.com/>"
@@ -3113,7 +3678,7 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
3113
3678
  size_t len = 13+((RSTRING_LEN(url) > 50) ? 50 : RSTRING_LEN(url));
3114
3679
  /* "#<Net::HTTP http://www.google.com/:80 open=false>" */
3115
3680
  memcpy(buf,"#<Curl::Easy ", 13);
3116
- memcpy(buf+13,RSTRING_PTR(url), (len - 13));
3681
+ memcpy(buf+13,StringValueCStr(url), (len - 13));
3117
3682
  buf[len++] = '>';
3118
3683
  return rb_str_new(buf,len);
3119
3684
  }
@@ -3174,7 +3739,7 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
3174
3739
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
3175
3740
  result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
3176
3741
  #else
3177
- result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
3742
+ result = (char*)curl_unescape(StringValuePtr(str), (int)RSTRING_LEN(str));
3178
3743
  rlen = strlen(result);
3179
3744
  #endif
3180
3745
 
@@ -3189,114 +3754,14 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
3189
3754
 
3190
3755
  /*
3191
3756
  * call-seq:
3192
- * Curl::Easy.perform(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
3193
- *
3194
- * Convenience method that creates a new Curl::Easy instance with
3195
- * the specified URL and calls the general +perform+ method, before returning
3196
- * the new instance. For HTTP URLs, this is equivalent to calling +http_get+.
3757
+ * Curl::Easy.error(code) => [ErrCode, String]
3197
3758
  *
3198
- * If a block is supplied, the new instance will be yielded just prior to
3199
- * the +http_get+ call.
3759
+ * translate an internal libcurl error to ruby error class
3200
3760
  */
3201
- static VALUE ruby_curl_easy_class_perform(int argc, VALUE *argv, VALUE klass) {
3202
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
3203
-
3204
- if (rb_block_given_p()) {
3205
- rb_yield(c);
3206
- }
3207
-
3208
- ruby_curl_easy_perform(c);
3209
- return c;
3761
+ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
3762
+ return rb_curl_easy_error(NUM2INT(code));
3210
3763
  }
3211
3764
 
3212
- /*
3213
- * call-seq:
3214
- * Curl::Easy.http_get(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
3215
- *
3216
- * Convenience method that creates a new Curl::Easy instance with
3217
- * the specified URL and calls +http_get+, before returning the new instance.
3218
- *
3219
- * If a block is supplied, the new instance will be yielded just prior to
3220
- * the +http_get+ call.
3221
- */
3222
- static VALUE ruby_curl_easy_class_perform_get(int argc, VALUE *argv, VALUE klass) {
3223
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
3224
-
3225
- ruby_curl_easy_perform_get(c);
3226
- return c;
3227
- }
3228
-
3229
- /*
3230
- * call-seq:
3231
- * Curl::Easy.http_delete(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
3232
- *
3233
- * Convenience method that creates a new Curl::Easy instance with
3234
- * the specified URL and calls +http_delete+, before returning the new instance.
3235
- *
3236
- * If a block is supplied, the new instance will be yielded just prior to
3237
- * the +http_delete+ call.
3238
- */
3239
- static VALUE ruby_curl_easy_class_perform_delete(int argc, VALUE *argv, VALUE klass) {
3240
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
3241
-
3242
- ruby_curl_easy_perform_delete(c);
3243
- return c;
3244
- }
3245
-
3246
- /*
3247
- * call-seq:
3248
- * Curl::Easy.http_head(url) { |easy| ... } => #&lt;Curl::Easy...&gt;
3249
- *
3250
- * Convenience method that creates a new Curl::Easy instance with
3251
- * the specified URL and calls +http_head+, before returning the new instance.
3252
- *
3253
- * If a block is supplied, the new instance will be yielded just prior to
3254
- * the +http_head+ call.
3255
- */
3256
- static VALUE ruby_curl_easy_class_perform_head(int argc, VALUE *argv, VALUE klass) {
3257
- VALUE c = ruby_curl_easy_new(argc, argv, klass);
3258
-
3259
- ruby_curl_easy_perform_head(c);
3260
-
3261
- return c;
3262
- }
3263
-
3264
- // TODO: add convenience method for http_post
3265
-
3266
- /*
3267
- * call-seq:
3268
- * Curl::Easy.http_post(url, "some=urlencoded%20form%20data&and=so%20on") => true
3269
- * Curl::Easy.http_post(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
3270
- * Curl::Easy.http_post(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
3271
- * Curl::Easy.http_post(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
3272
- *
3273
- * POST the specified formdata to the currently configured URL using
3274
- * the current options set for this Curl::Easy instance. This method
3275
- * always returns true, or raises an exception (defined under
3276
- * Curl::Err) on error.
3277
- *
3278
- * If you wish to use multipart form encoding, you'll need to supply a block
3279
- * in order to set multipart_form_post true. See #http_post for more
3280
- * information.
3281
- */
3282
- static VALUE ruby_curl_easy_class_perform_post(int argc, VALUE *argv, VALUE klass) {
3283
- VALUE url, fields;
3284
- VALUE c;
3285
-
3286
- rb_scan_args(argc, argv, "1*", &url, &fields);
3287
-
3288
- c = ruby_curl_easy_new(1, &url, klass);
3289
-
3290
- if (argc > 1) {
3291
- ruby_curl_easy_perform_post(argc - 1, &argv[1], c);
3292
- } else {
3293
- ruby_curl_easy_perform_post(0, NULL, c);
3294
- }
3295
-
3296
- return c;
3297
- }
3298
-
3299
-
3300
3765
  /* =================== INIT LIB =====================*/
3301
3766
  void init_curb_easy() {
3302
3767
  idCall = rb_intern("call");
@@ -3308,32 +3773,26 @@ void init_curb_easy() {
3308
3773
  cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
3309
3774
 
3310
3775
  /* Class methods */
3311
- rb_define_singleton_method(cCurlEasy, "new", ruby_curl_easy_new, -1);
3312
- rb_define_singleton_method(cCurlEasy, "perform", ruby_curl_easy_class_perform, -1);
3313
- rb_define_singleton_method(cCurlEasy, "http_delete", ruby_curl_easy_class_perform_delete, -1);
3314
- rb_define_singleton_method(cCurlEasy, "http_get", ruby_curl_easy_class_perform_get, -1);
3315
- rb_define_singleton_method(cCurlEasy, "http_post", ruby_curl_easy_class_perform_post, -1);
3316
- rb_define_singleton_method(cCurlEasy, "http_head", ruby_curl_easy_class_perform_head, -1);
3317
- rb_define_singleton_method(cCurlEasy, "http_put", ruby_curl_easy_class_perform_put, 2);
3776
+ rb_define_alloc_func(cCurlEasy, ruby_curl_easy_allocate);
3777
+ rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
3778
+
3779
+ /* Initialize method */
3780
+ rb_define_method(cCurlEasy, "initialize", ruby_curl_easy_initialize, -1);
3318
3781
 
3319
3782
  /* Attributes for config next perform */
3320
- rb_define_method(cCurlEasy, "url=", ruby_curl_easy_url_set, 1);
3321
3783
  rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
3322
- rb_define_method(cCurlEasy, "proxy_url=", ruby_curl_easy_proxy_url_set, 1);
3323
3784
  rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
3785
+
3786
+ rb_define_method(cCurlEasy, "proxy_headers=", ruby_curl_easy_proxy_headers_set, 1);
3787
+ rb_define_method(cCurlEasy, "proxy_headers", ruby_curl_easy_proxy_headers_get, 0);
3788
+
3324
3789
  rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
3325
3790
  rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
3326
- rb_define_method(cCurlEasy, "interface=", ruby_curl_easy_interface_set, 1);
3327
3791
  rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
3328
- rb_define_method(cCurlEasy, "userpwd=", ruby_curl_easy_userpwd_set, 1);
3329
3792
  rb_define_method(cCurlEasy, "userpwd", ruby_curl_easy_userpwd_get, 0);
3330
- rb_define_method(cCurlEasy, "proxypwd=", ruby_curl_easy_proxypwd_set, 1);
3331
3793
  rb_define_method(cCurlEasy, "proxypwd", ruby_curl_easy_proxypwd_get, 0);
3332
- rb_define_method(cCurlEasy, "cookies=", ruby_curl_easy_cookies_set, 1);
3333
3794
  rb_define_method(cCurlEasy, "cookies", ruby_curl_easy_cookies_get, 0);
3334
- rb_define_method(cCurlEasy, "cookiefile=", ruby_curl_easy_cookiefile_set, 1);
3335
3795
  rb_define_method(cCurlEasy, "cookiefile", ruby_curl_easy_cookiefile_get, 0);
3336
- rb_define_method(cCurlEasy, "cookiejar=", ruby_curl_easy_cookiejar_set, 1);
3337
3796
  rb_define_method(cCurlEasy, "cookiejar", ruby_curl_easy_cookiejar_get, 0);
3338
3797
  rb_define_method(cCurlEasy, "cert=", ruby_curl_easy_cert_set, 1);
3339
3798
  rb_define_method(cCurlEasy, "cert", ruby_curl_easy_cert_get, 0);
@@ -3353,6 +3812,8 @@ void init_curb_easy() {
3353
3812
  rb_define_method(cCurlEasy, "put_data=", ruby_curl_easy_put_data_set, 1);
3354
3813
  rb_define_method(cCurlEasy, "ftp_commands=", ruby_curl_easy_ftp_commands_set, 1);
3355
3814
  rb_define_method(cCurlEasy, "ftp_commands", ruby_curl_easy_ftp_commands_get, 0);
3815
+ rb_define_method(cCurlEasy, "resolve=", ruby_curl_easy_resolve_set, 1);
3816
+ rb_define_method(cCurlEasy, "resolve", ruby_curl_easy_resolve_get, 0);
3356
3817
 
3357
3818
  rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
3358
3819
  rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
@@ -3370,8 +3831,12 @@ void init_curb_easy() {
3370
3831
  rb_define_method(cCurlEasy, "max_redirects", ruby_curl_easy_max_redirects_get, 0);
3371
3832
  rb_define_method(cCurlEasy, "timeout=", ruby_curl_easy_timeout_set, 1);
3372
3833
  rb_define_method(cCurlEasy, "timeout", ruby_curl_easy_timeout_get, 0);
3834
+ rb_define_method(cCurlEasy, "timeout_ms=", ruby_curl_easy_timeout_ms_set, 1);
3835
+ rb_define_method(cCurlEasy, "timeout_ms", ruby_curl_easy_timeout_ms_get, 0);
3373
3836
  rb_define_method(cCurlEasy, "connect_timeout=", ruby_curl_easy_connect_timeout_set, 1);
3374
3837
  rb_define_method(cCurlEasy, "connect_timeout", ruby_curl_easy_connect_timeout_get, 0);
3838
+ rb_define_method(cCurlEasy, "connect_timeout_ms=", ruby_curl_easy_connect_timeout_ms_set, 1);
3839
+ rb_define_method(cCurlEasy, "connect_timeout_ms", ruby_curl_easy_connect_timeout_ms_get, 0);
3375
3840
  rb_define_method(cCurlEasy, "dns_cache_timeout=", ruby_curl_easy_dns_cache_timeout_set, 1);
3376
3841
  rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
3377
3842
  rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
@@ -3380,6 +3845,10 @@ void init_curb_easy() {
3380
3845
  rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
3381
3846
  rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
3382
3847
  rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
3848
+ rb_define_method(cCurlEasy, "max_send_speed_large=", ruby_curl_easy_max_send_speed_large_set, 1);
3849
+ rb_define_method(cCurlEasy, "max_send_speed_large", ruby_curl_easy_max_send_speed_large_get, 0);
3850
+ rb_define_method(cCurlEasy, "max_recv_speed_large=", ruby_curl_easy_max_recv_speed_large_set, 1);
3851
+ rb_define_method(cCurlEasy, "max_recv_speed_large", ruby_curl_easy_max_recv_speed_large_get, 0);
3383
3852
  rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
3384
3853
  rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
3385
3854
  rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
@@ -3398,13 +3867,12 @@ void init_curb_easy() {
3398
3867
  rb_define_method(cCurlEasy, "fetch_file_time?", ruby_curl_easy_fetch_file_time_q, 0);
3399
3868
  rb_define_method(cCurlEasy, "ssl_verify_peer=", ruby_curl_easy_ssl_verify_peer_set, 1);
3400
3869
  rb_define_method(cCurlEasy, "ssl_verify_peer?", ruby_curl_easy_ssl_verify_peer_q, 0);
3401
- rb_define_method(cCurlEasy, "ssl_verify_host=", ruby_curl_easy_ssl_verify_host_set, 1);
3402
- rb_define_method(cCurlEasy, "ssl_verify_host?", ruby_curl_easy_ssl_verify_host_q, 0);
3870
+ rb_define_method(cCurlEasy, "ssl_verify_host_integer=", ruby_curl_easy_ssl_verify_host_set, 1);
3871
+ rb_define_method(cCurlEasy, "ssl_verify_host", ruby_curl_easy_ssl_verify_host_get, 0);
3403
3872
  rb_define_method(cCurlEasy, "header_in_body=", ruby_curl_easy_header_in_body_set, 1);
3404
3873
  rb_define_method(cCurlEasy, "header_in_body?", ruby_curl_easy_header_in_body_q, 0);
3405
3874
  rb_define_method(cCurlEasy, "use_netrc=", ruby_curl_easy_use_netrc_set, 1);
3406
3875
  rb_define_method(cCurlEasy, "use_netrc?", ruby_curl_easy_use_netrc_q, 0);
3407
- rb_define_method(cCurlEasy, "follow_location=", ruby_curl_easy_follow_location_set, 1);
3408
3876
  rb_define_method(cCurlEasy, "follow_location?", ruby_curl_easy_follow_location_q, 0);
3409
3877
  rb_define_method(cCurlEasy, "autoreferer=", ruby_curl_easy_autoreferer_set, 1);
3410
3878
  rb_define_method(cCurlEasy, "unrestricted_auth=", ruby_curl_easy_unrestricted_auth_set, 1);
@@ -3417,6 +3885,8 @@ void init_curb_easy() {
3417
3885
  rb_define_method(cCurlEasy, "enable_cookies?", ruby_curl_easy_enable_cookies_q, 0);
3418
3886
  rb_define_method(cCurlEasy, "ignore_content_length=", ruby_curl_easy_ignore_content_length_set, 1);
3419
3887
  rb_define_method(cCurlEasy, "ignore_content_length?", ruby_curl_easy_ignore_content_length_q, 0);
3888
+ rb_define_method(cCurlEasy, "resolve_mode", ruby_curl_easy_resolve_mode, 0);
3889
+ rb_define_method(cCurlEasy, "resolve_mode=", ruby_curl_easy_resolve_mode_set, 1);
3420
3890
 
3421
3891
  rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
3422
3892
  rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
@@ -3424,22 +3894,13 @@ void init_curb_easy() {
3424
3894
  rb_define_method(cCurlEasy, "on_debug", ruby_curl_easy_on_debug_set, -1);
3425
3895
  rb_define_method(cCurlEasy, "on_success", ruby_curl_easy_on_success_set, -1);
3426
3896
  rb_define_method(cCurlEasy, "on_failure", ruby_curl_easy_on_failure_set, -1);
3897
+ rb_define_method(cCurlEasy, "on_missing", ruby_curl_easy_on_missing_set, -1);
3898
+ rb_define_method(cCurlEasy, "on_redirect", ruby_curl_easy_on_redirect_set, -1);
3427
3899
  rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
3428
3900
 
3429
- rb_define_method(cCurlEasy, "perform", ruby_curl_easy_perform, 0);
3430
3901
  rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
3431
- rb_define_method(cCurlEasy, "http_delete", ruby_curl_easy_perform_delete, 0);
3432
- rb_define_method(cCurlEasy, "http_get", ruby_curl_easy_perform_get, 0);
3433
3902
  rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
3434
- rb_define_method(cCurlEasy, "http_head", ruby_curl_easy_perform_head, 0);
3435
3903
  rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
3436
- rb_define_method(cCurlEasy, "head=", ruby_curl_easy_set_head_option, 1);
3437
- rb_define_method(cCurlEasy, "delete=", ruby_curl_easy_set_delete_option, 1);
3438
- rb_define_method(cCurlEasy, "version=", ruby_curl_easy_set_version, 1);
3439
- rb_define_const(mCurl, "HTTP_1_1", LONG2NUM(CURL_HTTP_VERSION_1_1));
3440
- rb_define_const(mCurl, "HTTP_1_0", LONG2NUM(CURL_HTTP_VERSION_1_0));
3441
- rb_define_const(mCurl, "HTTP_NONE", LONG2NUM(CURL_HTTP_VERSION_NONE));
3442
- rb_define_method(cCurlEasy, "nosignal=", ruby_curl_easy_set_nosignal, 1);
3443
3904
 
3444
3905
  /* Post-perform info methods */
3445
3906
  rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
@@ -3455,10 +3916,14 @@ void init_curb_easy() {
3455
3916
  rb_define_method(cCurlEasy, "total_time", ruby_curl_easy_total_time_get, 0);
3456
3917
  rb_define_method(cCurlEasy, "name_lookup_time", ruby_curl_easy_name_lookup_time_get, 0);
3457
3918
  rb_define_method(cCurlEasy, "connect_time", ruby_curl_easy_connect_time_get, 0);
3919
+ #if defined(HAVE_CURLINFO_APPCONNECT_TIME)
3920
+ rb_define_method(cCurlEasy, "app_connect_time", ruby_curl_easy_app_connect_time_get, 0);
3921
+ #endif
3458
3922
  rb_define_method(cCurlEasy, "pre_transfer_time", ruby_curl_easy_pre_transfer_time_get, 0);
3459
3923
  rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
3460
3924
  rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
3461
3925
  rb_define_method(cCurlEasy, "redirect_count", ruby_curl_easy_redirect_count_get, 0);
3926
+ rb_define_method(cCurlEasy, "redirect_url", ruby_curl_easy_redirect_url_get, 0);
3462
3927
  rb_define_method(cCurlEasy, "downloaded_bytes", ruby_curl_easy_downloaded_bytes_get, 0);
3463
3928
  rb_define_method(cCurlEasy, "uploaded_bytes", ruby_curl_easy_uploaded_bytes_get, 0);
3464
3929
  rb_define_method(cCurlEasy, "download_speed", ruby_curl_easy_download_speed_get, 0);
@@ -3471,6 +3936,7 @@ void init_curb_easy() {
3471
3936
  rb_define_method(cCurlEasy, "content_type", ruby_curl_easy_content_type_get, 0);
3472
3937
  rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
3473
3938
  rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
3939
+ rb_define_method(cCurlEasy, "cookielist", ruby_curl_easy_cookielist_get, 0);
3474
3940
  rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
3475
3941
 
3476
3942
  rb_define_method(cCurlEasy, "close", ruby_curl_easy_close, 0);
@@ -3484,4 +3950,12 @@ void init_curb_easy() {
3484
3950
  rb_define_method(cCurlEasy, "clone", ruby_curl_easy_clone, 0);
3485
3951
  rb_define_alias(cCurlEasy, "dup", "clone");
3486
3952
  rb_define_method(cCurlEasy, "inspect", ruby_curl_easy_inspect, 0);
3953
+
3954
+ rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
3955
+ rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
3956
+ rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
3957
+ rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
3958
+
3959
+ rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
3960
+ rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
3487
3961
  }