curb 0.7.15 → 0.8.3

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
@@ -28,6 +28,10 @@ VALUE cCurlEasy;
28
28
 
29
29
  /* ================== CURL HANDLER FUNCS ==============*/
30
30
 
31
+ static VALUE callback_exception(VALUE unused) {
32
+ return Qfalse;
33
+ }
34
+
31
35
  /* These handle both body and header data */
32
36
  static size_t default_data_handler(char *stream,
33
37
  size_t size,
@@ -111,27 +115,81 @@ static size_t proc_data_handler(char *stream,
111
115
  }
112
116
  }
113
117
 
118
+ static size_t proc_data_handler_body(char *stream,
119
+ size_t size,
120
+ size_t nmemb,
121
+ ruby_curl_easy *rbce)
122
+ {
123
+ size_t ret;
124
+ rbce->callback_active = 1;
125
+ ret = proc_data_handler(stream, size, nmemb, rb_easy_get("body_proc"));
126
+ rbce->callback_active = 0;
127
+ return ret;
128
+ }
129
+ static size_t proc_data_handler_header(char *stream,
130
+ size_t size,
131
+ size_t nmemb,
132
+ ruby_curl_easy *rbce)
133
+ {
134
+ size_t ret;
135
+ rbce->callback_active = 1;
136
+ ret = proc_data_handler(stream, size, nmemb, rb_easy_get("header_proc"));
137
+ rbce->callback_active = 0;
138
+ return ret;
139
+ }
140
+
141
+
142
+ static VALUE call_progress_handler(VALUE ary) {
143
+ return rb_funcall(rb_ary_entry(ary, 0), idCall, 4,
144
+ rb_ary_entry(ary, 1), // rb_float_new(dltotal),
145
+ rb_ary_entry(ary, 2), // rb_float_new(dlnow),
146
+ rb_ary_entry(ary, 3), // rb_float_new(ultotal),
147
+ rb_ary_entry(ary, 4)); // rb_float_new(ulnow));
148
+ }
149
+
114
150
  static int proc_progress_handler(VALUE proc,
115
151
  double dltotal,
116
152
  double dlnow,
117
153
  double ultotal,
118
154
  double ulnow) {
119
155
  VALUE procret;
156
+ VALUE callargs = rb_ary_new2(5);
120
157
 
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));
158
+ rb_ary_store(callargs, 0, proc);
159
+ rb_ary_store(callargs, 1, rb_float_new(dltotal));
160
+ rb_ary_store(callargs, 2, rb_float_new(dlnow));
161
+ rb_ary_store(callargs, 3, rb_float_new(ultotal));
162
+ rb_ary_store(callargs, 4, rb_float_new(ulnow));
163
+
164
+ //v = rb_rescue(range_check, (VALUE)args, range_failed, 0);
165
+ //procret = rb_funcall(proc, idCall, 4, rb_float_new(dltotal),
166
+ // rb_float_new(dlnow),
167
+ // rb_float_new(ultotal),
168
+ // rb_float_new(ulnow));
169
+ procret = rb_rescue(call_progress_handler, callargs, callback_exception, Qnil);
125
170
 
126
171
  return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
127
172
  }
128
173
 
174
+ static VALUE call_debug_handler(VALUE ary) {
175
+ return rb_funcall(rb_ary_entry(ary, 0), idCall, 2,
176
+ rb_ary_entry(ary, 1), // INT2FIX(type),
177
+ rb_ary_entry(ary, 2)); // rb_str_new(data, data_len)
178
+ }
129
179
  static int proc_debug_handler(CURL *curl,
130
180
  curl_infotype type,
131
181
  char *data,
132
182
  size_t data_len,
133
183
  VALUE proc) {
134
- rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
184
+ VALUE callargs = rb_ary_new2(3);
185
+ rb_ary_store(callargs, 0, proc);
186
+ rb_ary_store(callargs, 1, INT2FIX(type));
187
+ rb_ary_store(callargs, 2, rb_str_new(data, data_len));
188
+ rb_rescue(call_debug_handler, callargs, callback_exception, Qnil);
189
+ /* no way to indicate to libcurl that we should break out given an exception in the on_debug handler...
190
+ * this means exceptions will be swallowed
191
+ */
192
+ //rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
135
193
  return 0;
136
194
  }
137
195
 
@@ -186,12 +244,13 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
186
244
  rbce->ssl_version = -1;
187
245
  rbce->use_ssl = -1;
188
246
  rbce->ftp_filemethod = -1;
247
+ rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
189
248
 
190
249
  /* bool opts */
191
250
  rbce->proxy_tunnel = 0;
192
251
  rbce->fetch_file_time = 0;
193
252
  rbce->ssl_verify_peer = 1;
194
- rbce->ssl_verify_host = 1;
253
+ rbce->ssl_verify_host = 2;
195
254
  rbce->header_in_body = 0;
196
255
  rbce->use_netrc = 0;
197
256
  rbce->follow_location = 0;
@@ -200,6 +259,7 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
200
259
  rbce->multipart_form_post = 0;
201
260
  rbce->enable_cookies = 0;
202
261
  rbce->ignore_content_length = 0;
262
+ rbce->callback_active = 0;
203
263
  }
204
264
 
205
265
  /*
@@ -286,6 +346,10 @@ static VALUE ruby_curl_easy_close(VALUE self) {
286
346
 
287
347
  Data_Get_Struct(self, ruby_curl_easy, rbce);
288
348
 
349
+ if (rbce->callback_active) {
350
+ rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
351
+ }
352
+
289
353
  ruby_curl_easy_free(rbce);
290
354
 
291
355
  /* reinit the handle */
@@ -324,6 +388,11 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
324
388
  ruby_curl_easy *rbce;
325
389
  VALUE opts_dup;
326
390
  Data_Get_Struct(self, ruby_curl_easy, rbce);
391
+
392
+ if (rbce->callback_active) {
393
+ rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
394
+ }
395
+
327
396
  opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
328
397
 
329
398
  curl_easy_reset(rbce->curl);
@@ -347,18 +416,6 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
347
416
 
348
417
  /* ================ OBJ ATTRIBUTES ==================*/
349
418
 
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
419
  /*
363
420
  * call-seq:
364
421
  * easy.url => string
@@ -369,35 +426,6 @@ static VALUE ruby_curl_easy_url_get(VALUE self) {
369
426
  CURB_OBJECT_HGETTER(ruby_curl_easy, url);
370
427
  }
371
428
 
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
429
  /*
402
430
  * call-seq:
403
431
  * easy.proxy_url => string
@@ -449,17 +477,6 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
449
477
  return headers;
450
478
  }
451
479
 
452
- /*
453
- * call-seq:
454
- * easy.interface = string => string
455
- *
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.
458
- */
459
- static VALUE ruby_curl_easy_interface_set(VALUE self, VALUE interface_hm) {
460
- CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
461
- }
462
-
463
480
  /*
464
481
  * call-seq:
465
482
  * easy.interface => string
@@ -471,17 +488,6 @@ static VALUE ruby_curl_easy_interface_get(VALUE self) {
471
488
  CURB_OBJECT_HGETTER(ruby_curl_easy, interface_hm);
472
489
  }
473
490
 
474
- /*
475
- * call-seq:
476
- * easy.userpwd = string => string
477
- *
478
- * Set the username/password string to use for subsequent calls to +perform+.
479
- * The supplied string should have the form "username:password"
480
- */
481
- static VALUE ruby_curl_easy_userpwd_set(VALUE self, VALUE userpwd) {
482
- CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
483
- }
484
-
485
491
  /*
486
492
  * call-seq:
487
493
  * easy.userpwd => string
@@ -493,18 +499,6 @@ static VALUE ruby_curl_easy_userpwd_get(VALUE self) {
493
499
  CURB_OBJECT_HGETTER(ruby_curl_easy, userpwd);
494
500
  }
495
501
 
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
502
  /*
509
503
  * call-seq:
510
504
  * easy.proxypwd => string
@@ -517,19 +511,6 @@ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
517
511
  CURB_OBJECT_HGETTER(ruby_curl_easy, proxypwd);
518
512
  }
519
513
 
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
514
  /*
534
515
  * call-seq:
535
516
  * easy.cookies => "name1=content1; name2=content2;"
@@ -540,19 +521,6 @@ static VALUE ruby_curl_easy_cookies_get(VALUE self) {
540
521
  CURB_OBJECT_HGETTER(ruby_curl_easy, cookies);
541
522
  }
542
523
 
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
524
  /*
557
525
  * call-seq:
558
526
  * easy.cookiefile => string
@@ -563,20 +531,6 @@ static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
563
531
  CURB_OBJECT_HGETTER(ruby_curl_easy, cookiefile);
564
532
  }
565
533
 
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
534
  /*
581
535
  * call-seq:
582
536
  * easy.cookiejar => string
@@ -1453,7 +1407,7 @@ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1453
1407
 
1454
1408
  /*
1455
1409
  * call-seq:
1456
- * easy.ssl_verify_host = boolean => boolean
1410
+ * easy.ssl_verify_host = [0, 1, 2] => [0, 1, 2]
1457
1411
  *
1458
1412
  * Configure whether this Curl instance will verify that the server cert
1459
1413
  * is for the server it is known as. When true (the default) the server
@@ -1465,18 +1419,18 @@ static VALUE ruby_curl_easy_ssl_verify_peer_q(VALUE self) {
1465
1419
  * The server could be lying. To control lying, see ssl_verify_peer? .
1466
1420
  */
1467
1421
  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);
1422
+ CURB_IMMED_SETTER(ruby_curl_easy, ssl_verify_host, 0);
1469
1423
  }
1470
1424
 
1471
1425
  /*
1472
1426
  * call-seq:
1473
- * easy.ssl_verify_host? => boolean
1427
+ * easy.ssl_verify_host => number
1474
1428
  *
1475
1429
  * Determine whether this Curl instance will verify that the server cert
1476
1430
  * is for the server it is known as.
1477
1431
  */
1478
- static VALUE ruby_curl_easy_ssl_verify_host_q(VALUE self) {
1479
- CURB_BOOLEAN_GETTER(ruby_curl_easy, ssl_verify_host);
1432
+ static VALUE ruby_curl_easy_ssl_verify_host_get(VALUE self) {
1433
+ CURB_IMMED_GETTER(ruby_curl_easy, ssl_verify_host, 0);
1480
1434
  }
1481
1435
 
1482
1436
  /*
@@ -1524,17 +1478,6 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
1524
1478
  CURB_BOOLEAN_GETTER(ruby_curl_easy, use_netrc);
1525
1479
  }
1526
1480
 
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
1481
  /*
1539
1482
  * call-seq:
1540
1483
  *
@@ -1685,6 +1628,65 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
1685
1628
  CURB_BOOLEAN_GETTER(ruby_curl_easy, ignore_content_length);
1686
1629
  }
1687
1630
 
1631
+ /*
1632
+ * call-seq:
1633
+ * easy.resolve_mode => symbol
1634
+ *
1635
+ * Determines what type of IP address this Curl::Easy instance
1636
+ * resolves DNS names to.
1637
+ */
1638
+ static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
1639
+ ruby_curl_easy *rbce;
1640
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1641
+
1642
+ unsigned short rm = rbce->resolve_mode;
1643
+
1644
+ switch(rm) {
1645
+ case CURL_IPRESOLVE_V4:
1646
+ return rb_easy_sym("ipv4");
1647
+ case CURL_IPRESOLVE_V6:
1648
+ return rb_easy_sym("ipv6");
1649
+ default:
1650
+ return rb_easy_sym("auto");
1651
+ }
1652
+ }
1653
+
1654
+ /*
1655
+ * call-seq:
1656
+ * easy.resolve_mode = symbol => symbol
1657
+ *
1658
+ * Configures what type of IP address this Curl::Easy instance
1659
+ * resolves DNS names to. Valid options are:
1660
+ *
1661
+ * [:auto] resolves DNS names to all IP versions your system allows
1662
+ * [:ipv4] resolves DNS names to IPv4 only
1663
+ * [:ipv6] resolves DNS names to IPv6 only
1664
+ */
1665
+ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
1666
+ if (TYPE(resolve_mode) != T_SYMBOL) {
1667
+ rb_raise(rb_eTypeError, "Must pass a symbol");
1668
+ return Qnil;
1669
+ } else {
1670
+ ruby_curl_easy *rbce;
1671
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
1672
+
1673
+ ID resolve_mode_id = rb_to_id(resolve_mode);
1674
+
1675
+ if (resolve_mode_id == rb_intern("auto")) {
1676
+ rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
1677
+ return resolve_mode;
1678
+ } else if (resolve_mode_id == rb_intern("ipv4")) {
1679
+ rbce->resolve_mode = CURL_IPRESOLVE_V4;
1680
+ return resolve_mode;
1681
+ } else if (resolve_mode_id == rb_intern("ipv6")) {
1682
+ rbce->resolve_mode = CURL_IPRESOLVE_V6;
1683
+ return resolve_mode;
1684
+ } else {
1685
+ rb_raise(rb_eArgError, "Must set to one of :auto, :ipv4, :ipv6");
1686
+ return Qnil;
1687
+ }
1688
+ }
1689
+ }
1688
1690
 
1689
1691
 
1690
1692
  /* ================= EVENT PROCS ================== */
@@ -1738,6 +1740,36 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
1738
1740
  CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, failure_proc);
1739
1741
  }
1740
1742
 
1743
+ /*
1744
+ * call-seq:
1745
+ * easy.on_missing {|easy,code| ... } => <old handler;>
1746
+ *
1747
+ * Assign or remove the on_missing handler for this Curl::Easy instance.
1748
+ * To remove a previously-supplied handler, call this method with no attached
1749
+ * block.
1750
+ *
1751
+ * The +on_missing+ handler is called when request is finished with a
1752
+ * status of 40x
1753
+ */
1754
+ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
1755
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, missing_proc);
1756
+ }
1757
+
1758
+ /*
1759
+ * call-seq:
1760
+ * easy.on_redirect {|easy,code| ... } => <old handler;>
1761
+ *
1762
+ * Assign or remove the on_redirect handler for this Curl::Easy instance.
1763
+ * To remove a previously-supplied handler, call this method with no attached
1764
+ * block.
1765
+ *
1766
+ * The +on_redirect+ handler is called when request is finished with a
1767
+ * status of 30x
1768
+ */
1769
+ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
1770
+ CURB_HANDLER_PROC_HSETTER(ruby_curl_easy, redirect_proc);
1771
+ }
1772
+
1741
1773
  /*
1742
1774
  * call-seq:
1743
1775
  * easy.on_complete {|easy| ... } => <old handler>
@@ -1816,7 +1848,10 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
1816
1848
  /***********************************************
1817
1849
  * This is an rb_iterate callback used to set up http headers.
1818
1850
  */
1819
- static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1851
+ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
1852
+ struct curl_slist **list;
1853
+ Data_Get_Struct(wrap, struct curl_slist *, list);
1854
+
1820
1855
  VALUE header_str = Qnil;
1821
1856
 
1822
1857
  //rb_p(header);
@@ -1845,7 +1880,10 @@ static VALUE cb_each_http_header(VALUE header, struct curl_slist **list) {
1845
1880
  /***********************************************
1846
1881
  * This is an rb_iterate callback used to set up ftp commands.
1847
1882
  */
1848
- static VALUE cb_each_ftp_command(VALUE ftp_command, struct curl_slist **list) {
1883
+ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
1884
+ struct curl_slist **list;
1885
+ Data_Get_Struct(wrap, struct curl_slist *, list);
1886
+
1849
1887
  VALUE ftp_command_string = rb_obj_as_string(ftp_command);
1850
1888
  *list = curl_slist_append(*list, StringValuePtr(ftp_command));
1851
1889
 
@@ -1858,7 +1896,7 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, struct curl_slist **list) {
1858
1896
  *
1859
1897
  * Always returns Qtrue, rb_raise on error.
1860
1898
  */
1861
- VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1899
+ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
1862
1900
  // TODO this could do with a bit of refactoring...
1863
1901
  CURL *curl;
1864
1902
  VALUE url, _url = rb_easy_get("url");
@@ -1873,7 +1911,6 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1873
1911
 
1874
1912
  url = rb_check_string_type(_url);
1875
1913
 
1876
- // Need to configure the handler as per settings in rbce
1877
1914
  curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
1878
1915
 
1879
1916
  // network stuff and auth
@@ -1921,8 +1958,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1921
1958
 
1922
1959
  // body/header procs
1923
1960
  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);
1961
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
1962
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
1926
1963
  /* clear out the body_data if it was set */
1927
1964
  rb_easy_del("body_data");
1928
1965
  } else {
@@ -1932,8 +1969,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1932
1969
  }
1933
1970
 
1934
1971
  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"));
1972
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler_header);
1973
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
1937
1974
  /* clear out the header_data if it was set */
1938
1975
  rb_easy_del("header_data");
1939
1976
  } else {
@@ -1976,12 +2013,12 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1976
2013
  curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
1977
2014
  curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
1978
2015
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
1979
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_peer);
2016
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_host);
1980
2017
 
1981
2018
  if ((rbce->use_netrc != Qnil) && (rbce->use_netrc != Qfalse)) {
1982
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_OPTIONAL);
2019
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
1983
2020
  } else {
1984
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, CURL_NETRC_IGNORED);
2021
+ curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
1985
2022
  }
1986
2023
 
1987
2024
  curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
@@ -1992,6 +2029,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
1992
2029
 
1993
2030
  curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
1994
2031
 
2032
+ curl_easy_setopt(curl, CURLOPT_IPRESOLVE, rbce->resolve_mode);
2033
+
1995
2034
 
1996
2035
  #if LIBCURL_VERSION_NUM >= 0x070a08
1997
2036
  curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
@@ -2077,7 +2116,9 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2077
2116
 
2078
2117
  /* Set up HTTPS cert handling if necessary */
2079
2118
  if (!rb_easy_nil("cert")) {
2080
- curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2119
+ if (!rb_easy_nil("certtype")) {
2120
+ curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, rb_easy_get_str("certtype"));
2121
+ }
2081
2122
  curl_easy_setopt(curl, CURLOPT_SSLCERT, rb_easy_get_str("cert"));
2082
2123
  if (!rb_easy_nil("certpassword")) {
2083
2124
  curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, rb_easy_get_str("certpassword"));
@@ -2086,13 +2127,15 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2086
2127
  curl_easy_setopt(curl, CURLOPT_SSLKEY, rb_easy_get_str("cert_key"));
2087
2128
  }
2088
2129
  }
2130
+
2089
2131
  if (!rb_easy_nil("cacert")) {
2132
+ curl_easy_setopt(curl, CURLOPT_CAINFO, rb_easy_get_str("cacert"));
2133
+ }
2090
2134
  #ifdef HAVE_CURL_CONFIG_CA
2135
+ else {
2091
2136
  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
2137
  }
2138
+ #endif
2096
2139
 
2097
2140
  #ifdef CURL_VERSION_SSL
2098
2141
  if (rbce->ssl_version > 0) {
@@ -2122,7 +2165,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2122
2165
 
2123
2166
  if (!rb_easy_nil("headers")) {
2124
2167
  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);
2168
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, hdrs);
2169
+ rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, wrap);
2126
2170
  } else {
2127
2171
  VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
2128
2172
  *hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
@@ -2136,7 +2180,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
2136
2180
  /* Setup FTP commands if necessary */
2137
2181
  if (!rb_easy_nil("ftp_commands")) {
2138
2182
  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);
2183
+ VALUE wrap = Data_Wrap_Struct(rb_cObject, 0, 0, cmds);
2184
+ rb_iterate(rb_each, rb_easy_get("ftp_commands"), cb_each_ftp_command, wrap);
2140
2185
  }
2141
2186
 
2142
2187
  if (*cmds) {
@@ -2181,56 +2226,6 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
2181
2226
  return Qnil;
2182
2227
  }
2183
2228
 
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);
2230
-
2231
- return handle_perform(self,rbce);
2232
- }
2233
-
2234
2229
  /*
2235
2230
  * Common implementation of easy.http(verb) and easy.http_delete
2236
2231
  */
@@ -2244,25 +2239,13 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
2244
2239
 
2245
2240
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
2246
2241
 
2247
- retval = handle_perform(self,rbce);
2242
+ retval = rb_funcall(self, rb_intern("perform"), 0);
2248
2243
 
2249
2244
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2250
2245
 
2251
2246
  return retval;
2252
2247
  }
2253
2248
 
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
2249
  /*
2267
2250
  * call-seq:
2268
2251
  * easy.http(verb)
@@ -2273,33 +2256,17 @@ static VALUE ruby_curl_easy_perform_delete(VALUE self) {
2273
2256
  static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
2274
2257
  VALUE str_verb;
2275
2258
  if (rb_type(verb) == T_STRING) {
2276
- return ruby_curl_easy_perform_verb_str(self, RSTRING_PTR(verb));
2259
+ return ruby_curl_easy_perform_verb_str(self, StringValueCStr(verb));
2277
2260
  }
2278
2261
  else if (rb_respond_to(verb,rb_intern("to_s"))) {
2279
2262
  str_verb = rb_funcall(verb, rb_intern("to_s"), 0);
2280
- return ruby_curl_easy_perform_verb_str(self, RSTRING_PTR(str_verb));
2263
+ return ruby_curl_easy_perform_verb_str(self, StringValueCStr(str_verb));
2281
2264
  }
2282
2265
  else {
2283
2266
  rb_raise(rb_eRuntimeError, "Invalid HTTP VERB, must response to 'to_s'");
2284
2267
  }
2285
2268
  }
2286
2269
 
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
2270
  /*
2304
2271
  * call-seq:
2305
2272
  * easy.http_post("url=encoded%20form%20data;and=so%20on") => true
@@ -2345,6 +2312,17 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2345
2312
  for (i = 0; i < argc; i++) {
2346
2313
  if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
2347
2314
  append_to_form(argv[i], &first, &last);
2315
+ } else if (rb_type(argv[i]) == T_ARRAY) {
2316
+ // see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
2317
+ int c = 0, argv_len = (int)RARRAY_LEN(argv[i]);
2318
+ for (; c < argv_len; ++c) {
2319
+ if (rb_obj_is_instance_of(rb_ary_entry(argv[i],c), cCurlPostField)) {
2320
+ append_to_form(rb_ary_entry(argv[i],c), &first, &last);
2321
+ } else {
2322
+ rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
2323
+ return Qnil;
2324
+ }
2325
+ }
2348
2326
  } else {
2349
2327
  rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
2350
2328
  return Qnil;
@@ -2353,7 +2331,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2353
2331
 
2354
2332
  curl_easy_setopt(curl, CURLOPT_POST, 0);
2355
2333
  curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
2356
- ret = handle_perform(self,rbce);
2334
+ ret = rb_funcall(self, rb_intern("perform"), 0);
2357
2335
  curl_formfree(first);
2358
2336
 
2359
2337
  return ret;
@@ -2375,114 +2353,11 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2375
2353
  ruby_curl_easy_post_body_set(self, post_body);
2376
2354
  }
2377
2355
 
2378
- return handle_perform(self,rbce);
2356
+ return rb_funcall(self, rb_intern("perform"), 0);
2379
2357
  }
2380
2358
  }
2381
2359
  }
2382
2360
 
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
2361
  /*
2487
2362
  * call-seq:
2488
2363
  * easy.http_put(data) => true
@@ -2494,28 +2369,17 @@ static VALUE ruby_curl_easy_set_delete_option(VALUE self, VALUE onoff) {
2494
2369
  static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
2495
2370
  ruby_curl_easy *rbce;
2496
2371
  CURL *curl;
2497
-
2372
+
2498
2373
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2499
2374
  curl = rbce->curl;
2500
-
2375
+
2501
2376
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2502
2377
  ruby_curl_easy_put_data_set(self, data);
2503
-
2504
- return handle_perform(self, rbce);
2505
- }
2506
2378
 
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;
2379
+ return rb_funcall(self, rb_intern("perform"), 0);
2517
2380
  }
2518
2381
 
2382
+
2519
2383
  /* =================== DATA FUNCS =============== */
2520
2384
 
2521
2385
  /*
@@ -2801,6 +2665,36 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
2801
2665
 
2802
2666
  }
2803
2667
 
2668
+ /*
2669
+ * call-seq:
2670
+ * easy.redirect_url => "http://some.url" or nil
2671
+ *
2672
+ * Retrieve the URL a redirect would take you to if you
2673
+ * would enable CURLOPT_FOLLOWLOCATION.
2674
+ *
2675
+ * Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
2676
+ */
2677
+ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
2678
+ #ifdef HAVE_CURLINFO_REDIRECT_URL
2679
+ ruby_curl_easy *rbce;
2680
+ char* url;
2681
+
2682
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2683
+ curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
2684
+
2685
+ if (url && url[0]) { // curl returns empty string if none
2686
+ return rb_str_new2(url);
2687
+ } else {
2688
+ return Qnil;
2689
+ }
2690
+ #else
2691
+ rb_warn("Installed libcurl is too old to support redirect_url");
2692
+ return INT2FIX(-1);
2693
+ #endif
2694
+ }
2695
+
2696
+
2697
+
2804
2698
  /*
2805
2699
  * call-seq:
2806
2700
  * easy.uploaded_bytes => float
@@ -2923,7 +2817,10 @@ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
2923
2817
 
2924
2818
  /* TODO CURLINFO_SSL_ENGINES
2925
2819
 
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)
2820
+ Pass the address of a 'struct curl_slist *' to receive a linked-list of OpenSSL crypto-engines supported.
2821
+ Note that engines are normally implemented in separate dynamic libraries.
2822
+ Hence not all the returned engines may be available at run-time.
2823
+ 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
2824
  */
2928
2825
 
2929
2826
  /*
@@ -3099,6 +2996,139 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
3099
2996
  #endif
3100
2997
  }
3101
2998
 
2999
+ /*
3000
+ * call-seq:
3001
+ * easy.multi => "#<Curl::Multi>"
3002
+ */
3003
+ static VALUE ruby_curl_easy_multi_get(VALUE self) {
3004
+ ruby_curl_easy *rbce;
3005
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3006
+ return rbce->multi;
3007
+ }
3008
+
3009
+ /*
3010
+ * call-seq:
3011
+ * easy.multi=multi => "#<Curl::Multi>"
3012
+ */
3013
+ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
3014
+ ruby_curl_easy *rbce;
3015
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3016
+ rbce->multi = multi;
3017
+ return rbce->multi;
3018
+ }
3019
+
3020
+ /*
3021
+ * call-seq:
3022
+ * easy.last_result => 0
3023
+ */
3024
+ static VALUE ruby_curl_easy_last_result(VALUE self) {
3025
+ ruby_curl_easy *rbce;
3026
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3027
+ return INT2FIX(rbce->last_result);
3028
+ }
3029
+
3030
+ /*
3031
+ * call-seq:
3032
+ * easy.setopt Fixnum, value => value
3033
+ *
3034
+ * Iniital access to libcurl curl_easy_setopt
3035
+ */
3036
+ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3037
+ ruby_curl_easy *rbce;
3038
+ long option = FIX2LONG(opt);
3039
+
3040
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
3041
+
3042
+ switch (option) {
3043
+ /* BEHAVIOR OPTIONS */
3044
+ case CURLOPT_VERBOSE: {
3045
+ VALUE verbose = val;
3046
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, verbose);
3047
+ } break;
3048
+ case CURLOPT_FOLLOWLOCATION: {
3049
+ VALUE follow_location = val;
3050
+ CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
3051
+ } break;
3052
+ /* TODO: CALLBACK OPTIONS */
3053
+ /* TODO: ERROR OPTIONS */
3054
+ /* NETWORK OPTIONS */
3055
+ case CURLOPT_URL: {
3056
+ VALUE url = val;
3057
+ CURB_OBJECT_HSETTER(ruby_curl_easy, url);
3058
+ } break;
3059
+ case CURLOPT_CUSTOMREQUEST:
3060
+ curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NIL_P(val) ? NULL : StringValueCStr(val));
3061
+ break;
3062
+ case CURLOPT_HTTP_VERSION:
3063
+ curl_easy_setopt(rbce->curl, CURLOPT_HTTP_VERSION, FIX2INT(val));
3064
+ break;
3065
+ case CURLOPT_PROXY: {
3066
+ VALUE proxy_url = val;
3067
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
3068
+ } break;
3069
+ case CURLOPT_INTERFACE: {
3070
+ VALUE interface_hm = val;
3071
+ CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
3072
+ } break;
3073
+ case CURLOPT_HEADER:
3074
+ case CURLOPT_NOPROGRESS:
3075
+ case CURLOPT_NOSIGNAL:
3076
+ case CURLOPT_HTTPGET:
3077
+ case CURLOPT_NOBODY: {
3078
+ int type = rb_type(val);
3079
+ VALUE value;
3080
+ if (type == T_TRUE) {
3081
+ value = rb_int_new(1);
3082
+ } else if (type == T_FALSE) {
3083
+ value = rb_int_new(0);
3084
+ } else {
3085
+ value = rb_funcall(val, rb_intern("to_i"), 0);
3086
+ }
3087
+ curl_easy_setopt(rbce->curl, option, FIX2INT(value));
3088
+ } break;
3089
+ case CURLOPT_USERPWD: {
3090
+ VALUE userpwd = val;
3091
+ CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
3092
+ } break;
3093
+ case CURLOPT_PROXYUSERPWD: {
3094
+ VALUE proxypwd = val;
3095
+ CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
3096
+ } break;
3097
+ case CURLOPT_COOKIE: {
3098
+ VALUE cookies = val;
3099
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
3100
+ } break;
3101
+ case CURLOPT_COOKIEFILE: {
3102
+ VALUE cookiefile = val;
3103
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookiefile);
3104
+ } break;
3105
+ case CURLOPT_COOKIEJAR: {
3106
+ VALUE cookiejar = val;
3107
+ CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
3108
+ } break;
3109
+ case CURLOPT_RESUME_FROM: {
3110
+ curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, FIX2LONG(val));
3111
+ } break;
3112
+ case CURLOPT_FAILONERROR: {
3113
+ curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR, FIX2LONG(val));
3114
+ } break;
3115
+ default:
3116
+ break;
3117
+ }
3118
+
3119
+ return val;
3120
+ }
3121
+
3122
+ /*
3123
+ * call-seq:
3124
+ * easy.getinfo Fixnum => value
3125
+ *
3126
+ * Iniital access to libcurl curl_easy_getinfo, remember getinfo doesn't return the same values as setopt
3127
+ */
3128
+ static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
3129
+ return Qnil;
3130
+ }
3131
+
3102
3132
  /*
3103
3133
  * call-seq:
3104
3134
  * easy.inspect => "#<Curl::Easy http://google.com/>"
@@ -3113,7 +3143,7 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
3113
3143
  size_t len = 13+((RSTRING_LEN(url) > 50) ? 50 : RSTRING_LEN(url));
3114
3144
  /* "#<Net::HTTP http://www.google.com/:80 open=false>" */
3115
3145
  memcpy(buf,"#<Curl::Easy ", 13);
3116
- memcpy(buf+13,RSTRING_PTR(url), (len - 13));
3146
+ memcpy(buf+13,StringValueCStr(url), (len - 13));
3117
3147
  buf[len++] = '>';
3118
3148
  return rb_str_new(buf,len);
3119
3149
  }
@@ -3189,114 +3219,14 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
3189
3219
 
3190
3220
  /*
3191
3221
  * 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+.
3222
+ * Curl::Easy.error(code) => String
3197
3223
  *
3198
- * If a block is supplied, the new instance will be yielded just prior to
3199
- * the +http_get+ call.
3224
+ * translate an internal libcurl error to ruby error class
3200
3225
  */
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;
3226
+ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
3227
+ return rb_curl_easy_error(FIX2INT(code));
3210
3228
  }
3211
3229
 
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
3230
  /* =================== INIT LIB =====================*/
3301
3231
  void init_curb_easy() {
3302
3232
  idCall = rb_intern("call");
@@ -3309,31 +3239,18 @@ void init_curb_easy() {
3309
3239
 
3310
3240
  /* Class methods */
3311
3241
  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);
3242
+ rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
3318
3243
 
3319
3244
  /* Attributes for config next perform */
3320
- rb_define_method(cCurlEasy, "url=", ruby_curl_easy_url_set, 1);
3321
3245
  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
3246
  rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
3324
3247
  rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
3325
3248
  rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
3326
- rb_define_method(cCurlEasy, "interface=", ruby_curl_easy_interface_set, 1);
3327
3249
  rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
3328
- rb_define_method(cCurlEasy, "userpwd=", ruby_curl_easy_userpwd_set, 1);
3329
3250
  rb_define_method(cCurlEasy, "userpwd", ruby_curl_easy_userpwd_get, 0);
3330
- rb_define_method(cCurlEasy, "proxypwd=", ruby_curl_easy_proxypwd_set, 1);
3331
3251
  rb_define_method(cCurlEasy, "proxypwd", ruby_curl_easy_proxypwd_get, 0);
3332
- rb_define_method(cCurlEasy, "cookies=", ruby_curl_easy_cookies_set, 1);
3333
3252
  rb_define_method(cCurlEasy, "cookies", ruby_curl_easy_cookies_get, 0);
3334
- rb_define_method(cCurlEasy, "cookiefile=", ruby_curl_easy_cookiefile_set, 1);
3335
3253
  rb_define_method(cCurlEasy, "cookiefile", ruby_curl_easy_cookiefile_get, 0);
3336
- rb_define_method(cCurlEasy, "cookiejar=", ruby_curl_easy_cookiejar_set, 1);
3337
3254
  rb_define_method(cCurlEasy, "cookiejar", ruby_curl_easy_cookiejar_get, 0);
3338
3255
  rb_define_method(cCurlEasy, "cert=", ruby_curl_easy_cert_set, 1);
3339
3256
  rb_define_method(cCurlEasy, "cert", ruby_curl_easy_cert_get, 0);
@@ -3398,13 +3315,12 @@ void init_curb_easy() {
3398
3315
  rb_define_method(cCurlEasy, "fetch_file_time?", ruby_curl_easy_fetch_file_time_q, 0);
3399
3316
  rb_define_method(cCurlEasy, "ssl_verify_peer=", ruby_curl_easy_ssl_verify_peer_set, 1);
3400
3317
  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);
3318
+ rb_define_method(cCurlEasy, "ssl_verify_host_integer=", ruby_curl_easy_ssl_verify_host_set, 1);
3319
+ rb_define_method(cCurlEasy, "ssl_verify_host", ruby_curl_easy_ssl_verify_host_get, 0);
3403
3320
  rb_define_method(cCurlEasy, "header_in_body=", ruby_curl_easy_header_in_body_set, 1);
3404
3321
  rb_define_method(cCurlEasy, "header_in_body?", ruby_curl_easy_header_in_body_q, 0);
3405
3322
  rb_define_method(cCurlEasy, "use_netrc=", ruby_curl_easy_use_netrc_set, 1);
3406
3323
  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
3324
  rb_define_method(cCurlEasy, "follow_location?", ruby_curl_easy_follow_location_q, 0);
3409
3325
  rb_define_method(cCurlEasy, "autoreferer=", ruby_curl_easy_autoreferer_set, 1);
3410
3326
  rb_define_method(cCurlEasy, "unrestricted_auth=", ruby_curl_easy_unrestricted_auth_set, 1);
@@ -3417,6 +3333,8 @@ void init_curb_easy() {
3417
3333
  rb_define_method(cCurlEasy, "enable_cookies?", ruby_curl_easy_enable_cookies_q, 0);
3418
3334
  rb_define_method(cCurlEasy, "ignore_content_length=", ruby_curl_easy_ignore_content_length_set, 1);
3419
3335
  rb_define_method(cCurlEasy, "ignore_content_length?", ruby_curl_easy_ignore_content_length_q, 0);
3336
+ rb_define_method(cCurlEasy, "resolve_mode", ruby_curl_easy_resolve_mode, 0);
3337
+ rb_define_method(cCurlEasy, "resolve_mode=", ruby_curl_easy_resolve_mode_set, 1);
3420
3338
 
3421
3339
  rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
3422
3340
  rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
@@ -3424,22 +3342,13 @@ void init_curb_easy() {
3424
3342
  rb_define_method(cCurlEasy, "on_debug", ruby_curl_easy_on_debug_set, -1);
3425
3343
  rb_define_method(cCurlEasy, "on_success", ruby_curl_easy_on_success_set, -1);
3426
3344
  rb_define_method(cCurlEasy, "on_failure", ruby_curl_easy_on_failure_set, -1);
3345
+ rb_define_method(cCurlEasy, "on_missing", ruby_curl_easy_on_missing_set, -1);
3346
+ rb_define_method(cCurlEasy, "on_redirect", ruby_curl_easy_on_redirect_set, -1);
3427
3347
  rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
3428
3348
 
3429
- rb_define_method(cCurlEasy, "perform", ruby_curl_easy_perform, 0);
3430
3349
  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
3350
  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
3351
  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
3352
 
3444
3353
  /* Post-perform info methods */
3445
3354
  rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
@@ -3459,6 +3368,7 @@ void init_curb_easy() {
3459
3368
  rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
3460
3369
  rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
3461
3370
  rb_define_method(cCurlEasy, "redirect_count", ruby_curl_easy_redirect_count_get, 0);
3371
+ rb_define_method(cCurlEasy, "redirect_url", ruby_curl_easy_redirect_url_get, 0);
3462
3372
  rb_define_method(cCurlEasy, "downloaded_bytes", ruby_curl_easy_downloaded_bytes_get, 0);
3463
3373
  rb_define_method(cCurlEasy, "uploaded_bytes", ruby_curl_easy_uploaded_bytes_get, 0);
3464
3374
  rb_define_method(cCurlEasy, "download_speed", ruby_curl_easy_download_speed_get, 0);
@@ -3484,4 +3394,11 @@ void init_curb_easy() {
3484
3394
  rb_define_method(cCurlEasy, "clone", ruby_curl_easy_clone, 0);
3485
3395
  rb_define_alias(cCurlEasy, "dup", "clone");
3486
3396
  rb_define_method(cCurlEasy, "inspect", ruby_curl_easy_inspect, 0);
3397
+
3398
+ rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
3399
+ rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
3400
+ rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
3401
+
3402
+ rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
3403
+ rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
3487
3404
  }