curb 1.3.7 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/curb_easy.c CHANGED
@@ -66,6 +66,17 @@ static struct curl_slist *duplicate_curl_slist(struct curl_slist *list);
66
66
  static size_t proc_data_handler(char *stream, size_t size, size_t nmemb, VALUE proc);
67
67
  static int curb_array_includes_string(VALUE list, VALUE value);
68
68
 
69
+ static void curb_easy_apply_thread_defaults(ruby_curl_easy *rbce) {
70
+ #ifdef HAVE_CURLOPT_NOSIGNAL
71
+ CURLcode ecode = curl_easy_setopt(rbce->curl, CURLOPT_NOSIGNAL, 1L);
72
+ if (ecode != CURLE_OK) {
73
+ raise_curl_easy_error_exception(ecode);
74
+ }
75
+ #else
76
+ (void)rbce;
77
+ #endif
78
+ }
79
+
69
80
  /* ================== CURL HANDLER FUNCS ==============*/
70
81
 
71
82
  static int curb_ipv4_is_unsafe_destination(const unsigned char *ip) {
@@ -736,7 +747,7 @@ VALUE rb_curl_easy_take_callback_error(ruby_curl_easy *rbce) {
736
747
  static VALUE ruby_curl_easy_take_callback_error(VALUE self) {
737
748
  ruby_curl_easy *rbce = NULL;
738
749
 
739
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
750
+ rbce = ruby_curl_easy_get_handle(self);
740
751
  return rb_curl_easy_take_callback_error(rbce);
741
752
  }
742
753
 
@@ -1292,6 +1303,19 @@ static ruby_curl_multi *ruby_curl_multi_pointer_if_compatible(VALUE multi_val) {
1292
1303
  #endif
1293
1304
  }
1294
1305
 
1306
+ /* Explicit lifecycle operations can update Ruby bookkeeping; the GC free
1307
+ * path below must remain allocation-free. */
1308
+ static void ruby_curl_easy_detach(VALUE self, ruby_curl_easy *rbce) {
1309
+ VALUE multi = rbce->multi;
1310
+ ruby_curl_multi *rbcm = ruby_curl_multi_pointer_if_compatible(multi);
1311
+ if (rbcm) {
1312
+ CURLMcode result = rb_curl_multi_detach_easy(rbcm, rbce);
1313
+ if (result != CURLM_OK) raise_curl_multi_error_exception(result);
1314
+ rb_curl_multi_remove_request_reference(multi, self);
1315
+ }
1316
+ rbce->multi = Qnil;
1317
+ }
1318
+
1295
1319
  static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
1296
1320
  if (!rbce) {
1297
1321
  return;
@@ -1308,10 +1332,7 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
1308
1332
  * libcurl retaining a dangling pointer to a soon-to-be cleaned-up easy
1309
1333
  * handle. This path runs during GC, so it must not invoke Ruby APIs that
1310
1334
  * can allocate or raise. */
1311
- if (rbcm->handle && rbce->curl) {
1312
- curl_multi_remove_handle(rbcm->handle, rbce->curl);
1313
- }
1314
- rb_curl_multi_forget_easy(rbcm, rbce);
1335
+ rb_curl_multi_detach_easy(rbcm, rbce);
1315
1336
  }
1316
1337
  }
1317
1338
 
@@ -1385,6 +1406,39 @@ const rb_data_type_t ruby_curl_easy_data_type = {
1385
1406
  };
1386
1407
 
1387
1408
 
1409
+ void ruby_curl_easy_check_access(ruby_curl_easy *rbce) {
1410
+ if (rbce->multipart_building) {
1411
+ rb_raise(rb_eRuntimeError, "Cannot access an active curl handle during multipart construction");
1412
+ }
1413
+ rb_curl_multi_check_easy_thread(rbce);
1414
+ }
1415
+
1416
+ static void ruby_curl_easy_check_idle(ruby_curl_easy *rbce) {
1417
+ ruby_curl_easy_check_access(rbce);
1418
+ if (rb_curl_multi_easy_performing(rbce)) {
1419
+ rb_raise(rb_eRuntimeError, "Cannot modify an active curl handle during perform");
1420
+ }
1421
+ }
1422
+
1423
+ /* Public entry points must not pass an uninitialized handle to libcurl. */
1424
+ ruby_curl_easy *ruby_curl_easy_get_handle(VALUE self) {
1425
+ ruby_curl_easy *rbce;
1426
+ TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1427
+ if (!rbce->curl) {
1428
+ rb_raise(eCurlErrFailedInit, "Curl::Easy handle is not initialized");
1429
+ }
1430
+ ruby_curl_easy_check_access(rbce);
1431
+ return rbce;
1432
+ }
1433
+
1434
+ /* Keep libcurl's typed getinfo arguments while checking every result. */
1435
+ #define CURB_GETINFO(handle, info, output) do { \
1436
+ CURLcode info_result = curl_easy_getinfo(handle, info, output); \
1437
+ if (info_result != CURLE_OK) { \
1438
+ raise_curl_easy_error_exception(info_result); \
1439
+ } \
1440
+ } while (0)
1441
+
1388
1442
  /* ================= ALLOC METHODS ====================*/
1389
1443
 
1390
1444
  static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
@@ -1440,6 +1494,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
1440
1494
  rbce->unrestricted_auth = 0;
1441
1495
  rbce->verbose = 0;
1442
1496
  rbce->multipart_form_post = 0;
1497
+ rbce->multipart_form_active = 0;
1498
+ rbce->multipart_building = 0;
1443
1499
  rbce->enable_cookies = 0;
1444
1500
  rbce->cookielist_engine_enabled = 0;
1445
1501
  rbce->ignore_content_length = 0;
@@ -1489,6 +1545,16 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
1489
1545
 
1490
1546
  TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1491
1547
 
1548
+ if (rbce->callback_active || rbce->native_active) {
1549
+ rb_raise(rb_eRuntimeError, "Cannot initialize an active curl handle");
1550
+ }
1551
+
1552
+ ruby_curl_easy_check_idle(rbce);
1553
+ ruby_curl_easy_detach(self, rbce);
1554
+
1555
+ /* Detach and release any previous handle and its owned option lists. */
1556
+ ruby_curl_easy_free(rbce);
1557
+
1492
1558
  /* handler */
1493
1559
  rbce->curl = curl_easy_init();
1494
1560
  if (!rbce->curl) {
@@ -1501,6 +1567,7 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
1501
1567
  ruby_curl_easy_zero(rbce);
1502
1568
  rbce->self = self;
1503
1569
 
1570
+ curb_easy_apply_thread_defaults(rbce);
1504
1571
  curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
1505
1572
 
1506
1573
  rb_easy_set("url", url);
@@ -1559,11 +1626,13 @@ static VALUE duplicate_upload(VALUE upload) {
1559
1626
  *
1560
1627
  * Clone this Curl::Easy instance, creating a new instance.
1561
1628
  * This method duplicates the underlying CURL* handle.
1629
+ * A temporary multipart form attached during a request is not copied;
1630
+ * supply new PostFields to send a multipart request with the clone.
1562
1631
  */
1563
1632
  static VALUE ruby_curl_easy_clone(VALUE self) {
1564
1633
  ruby_curl_easy *rbce, *newrbce;
1565
1634
 
1566
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1635
+ rbce = ruby_curl_easy_get_handle(self);
1567
1636
 
1568
1637
  newrbce = ALLOC(ruby_curl_easy);
1569
1638
  if (!newrbce) {
@@ -1578,6 +1647,18 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
1578
1647
  free(newrbce);
1579
1648
  rb_raise(rb_eNoMemError, "Failed to duplicate Curl::Easy handle");
1580
1649
  }
1650
+ /* duphandle borrows HTTPPOST, whose form is freed when the original
1651
+ * perform unwinds. Only reset it when attached: setting HTTPPOST also
1652
+ * changes request options and must not affect ordinary POST/upload clones. */
1653
+ if (newrbce->multipart_form_active) {
1654
+ CURLcode ecode = curl_easy_setopt(newrbce->curl, CURLOPT_HTTPPOST, NULL);
1655
+ if (ecode != CURLE_OK) {
1656
+ curl_easy_cleanup(newrbce->curl);
1657
+ free(newrbce);
1658
+ raise_curl_easy_error_exception(ecode);
1659
+ }
1660
+ newrbce->multipart_form_active = 0;
1661
+ }
1581
1662
  newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
1582
1663
  newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
1583
1664
  newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
@@ -1591,6 +1672,7 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
1591
1672
  /* A cloned easy should not retain ownership reference to the original multi. */
1592
1673
  newrbce->multi = Qnil;
1593
1674
  newrbce->callback_error = Qnil;
1675
+ newrbce->callback_active = 0;
1594
1676
  newrbce->unsafe_destination_blocked = 0;
1595
1677
  memset(newrbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
1596
1678
  newrbce->native_active = 0;
@@ -1636,7 +1718,7 @@ static VALUE ruby_curl_easy_close(VALUE self) {
1636
1718
  CURLcode ecode;
1637
1719
  ruby_curl_easy *rbce;
1638
1720
 
1639
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1721
+ rbce = ruby_curl_easy_get_handle(self);
1640
1722
 
1641
1723
  if (rbce->callback_active) {
1642
1724
  rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
@@ -1646,6 +1728,9 @@ static VALUE ruby_curl_easy_close(VALUE self) {
1646
1728
  rb_raise(rb_eRuntimeError, "Cannot close an active curl handle during native operation");
1647
1729
  }
1648
1730
 
1731
+ ruby_curl_easy_check_idle(rbce);
1732
+ ruby_curl_easy_detach(self, rbce);
1733
+
1649
1734
  ruby_curl_easy_free(rbce);
1650
1735
 
1651
1736
  /* reinit the handle */
@@ -1659,6 +1744,7 @@ static VALUE ruby_curl_easy_close(VALUE self) {
1659
1744
  ruby_curl_easy_zero(rbce);
1660
1745
  rbce->self = self;
1661
1746
 
1747
+ curb_easy_apply_thread_defaults(rbce);
1662
1748
  curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, rbce->err_buf);
1663
1749
 
1664
1750
  /* give the new curl handle a reference back to the ruby object */
@@ -1686,7 +1772,7 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
1686
1772
  CURLcode ecode;
1687
1773
  ruby_curl_easy *rbce;
1688
1774
  VALUE opts_dup;
1689
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1775
+ rbce = ruby_curl_easy_get_handle(self);
1690
1776
 
1691
1777
  if (rbce->callback_active) {
1692
1778
  rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
@@ -1696,6 +1782,9 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
1696
1782
  rb_raise(rb_eRuntimeError, "Cannot reset an active curl handle during native operation");
1697
1783
  }
1698
1784
 
1785
+ ruby_curl_easy_check_idle(rbce);
1786
+ ruby_curl_easy_detach(self, rbce);
1787
+
1699
1788
  opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
1700
1789
 
1701
1790
  ruby_curl_easy_cleanup(self, rbce);
@@ -1703,6 +1792,7 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
1703
1792
  ruby_curl_easy_zero(rbce);
1704
1793
  rbce->self = self;
1705
1794
 
1795
+ curb_easy_apply_thread_defaults(rbce);
1706
1796
  curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
1707
1797
 
1708
1798
  /* reset clobbers the private setting, so reset it to self */
@@ -1776,7 +1866,7 @@ static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
1776
1866
  static VALUE ruby_curl_easy_headers_get(VALUE self) {
1777
1867
  ruby_curl_easy *rbce;
1778
1868
  VALUE headers;
1779
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1869
+ rbce = ruby_curl_easy_get_handle(self);
1780
1870
  headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
1781
1871
  if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
1782
1872
  return headers;
@@ -1811,7 +1901,7 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
1811
1901
  static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
1812
1902
  ruby_curl_easy *rbce;
1813
1903
  VALUE proxy_headers;
1814
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1904
+ rbce = ruby_curl_easy_get_handle(self);
1815
1905
  proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
1816
1906
  if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
1817
1907
  return proxy_headers;
@@ -2061,7 +2151,7 @@ static VALUE ruby_curl_easy_post_body_set_with_mode_body(VALUE argp) {
2061
2151
  char *data;
2062
2152
  long len;
2063
2153
 
2064
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2154
+ rbce = ruby_curl_easy_get_handle(self);
2065
2155
 
2066
2156
  curl = rbce->curl;
2067
2157
 
@@ -2120,7 +2210,7 @@ static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body,
2120
2210
  ruby_curl_easy *rbce;
2121
2211
  struct post_body_set_args args = { self, post_body, force_http_get_on_nil };
2122
2212
 
2123
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2213
+ rbce = ruby_curl_easy_get_handle(self);
2124
2214
  ruby_curl_easy_enter_native(rbce);
2125
2215
 
2126
2216
  return rb_ensure(ruby_curl_easy_post_body_set_with_mode_body, (VALUE)&args,
@@ -2157,7 +2247,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
2157
2247
  VALUE headers;
2158
2248
  VALUE infile_size = Qnil;
2159
2249
 
2160
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2250
+ rbce = ruby_curl_easy_get_handle(self);
2161
2251
 
2162
2252
  /*
2163
2253
  * Validate and prepare Ruby-visible state before mutating the CURL handle.
@@ -2342,7 +2432,7 @@ static VALUE ruby_curl_easy_dns_servers_get(VALUE self) {
2342
2432
  static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
2343
2433
  ruby_curl_easy *rbce;
2344
2434
 
2345
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2435
+ rbce = ruby_curl_easy_get_handle(self);
2346
2436
  rbce->allow_unix_socket = RTEST(allow) ? 1 : 0;
2347
2437
 
2348
2438
  return allow;
@@ -2351,7 +2441,7 @@ static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
2351
2441
  static VALUE ruby_curl_easy_allow_proxy_set(VALUE self, VALUE allow) {
2352
2442
  ruby_curl_easy *rbce;
2353
2443
 
2354
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2444
+ rbce = ruby_curl_easy_get_handle(self);
2355
2445
  rbce->allow_proxy = RTEST(allow) ? 1 : 0;
2356
2446
 
2357
2447
  return allow;
@@ -2370,7 +2460,7 @@ static VALUE ruby_curl_easy_allowed_cidrs_set(VALUE self, VALUE cidrs) {
2370
2460
  VALUE normalized;
2371
2461
  VALUE stored;
2372
2462
 
2373
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2463
+ rbce = ruby_curl_easy_get_handle(self);
2374
2464
  normalized = curb_normalize_cidr_list(cidrs);
2375
2465
  stored = curb_dup_string_array(normalized);
2376
2466
  rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_cidrs"), stored);
@@ -2391,7 +2481,7 @@ static VALUE ruby_curl_easy_allowed_cidrs_get(VALUE self) {
2391
2481
  ruby_curl_easy *rbce;
2392
2482
  VALUE cidrs;
2393
2483
 
2394
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2484
+ rbce = ruby_curl_easy_get_handle(self);
2395
2485
  cidrs = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_cidrs"));
2396
2486
 
2397
2487
  return curb_dup_string_array(cidrs);
@@ -2410,7 +2500,7 @@ static VALUE ruby_curl_easy_allowed_hosts_set(VALUE self, VALUE hosts) {
2410
2500
  VALUE normalized;
2411
2501
  VALUE stored;
2412
2502
 
2413
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2503
+ rbce = ruby_curl_easy_get_handle(self);
2414
2504
  normalized = curb_normalize_host_list(hosts);
2415
2505
  stored = curb_dup_string_array(normalized);
2416
2506
  rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_hosts"), stored);
@@ -2427,7 +2517,7 @@ static VALUE ruby_curl_easy_allowed_hosts_get(VALUE self) {
2427
2517
  ruby_curl_easy *rbce;
2428
2518
  VALUE hosts;
2429
2519
 
2430
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2520
+ rbce = ruby_curl_easy_get_handle(self);
2431
2521
  hosts = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_hosts"));
2432
2522
 
2433
2523
  return curb_dup_string_array(hosts);
@@ -2552,6 +2642,41 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
2552
2642
  (!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
2553
2643
  (!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
2554
2644
  #endif
2645
+ /*
2646
+ * Convert the arguments to http_auth_types= / proxy_auth_types= into a
2647
+ * CURLAUTH bitmask. Accepts nil, an Integer mask, or one or more auth type
2648
+ * names (symbols/strings), either as separate args or as a single Array.
2649
+ */
2650
+ static long ruby_curl_easy_auth_types_to_mask(VALUE args_ary) {
2651
+ long i, len;
2652
+ char* node = NULL;
2653
+ long mask = 0;
2654
+ VALUE first;
2655
+
2656
+ /* easy.http_auth_types = [:basic, :digest] arrives as a single Array arg */
2657
+ if (RARRAY_LEN(args_ary) == 1 && RB_TYPE_P(rb_ary_entry(args_ary,0), T_ARRAY)) {
2658
+ args_ary = rb_ary_entry(args_ary,0);
2659
+ }
2660
+
2661
+ len = RARRAY_LEN(args_ary);
2662
+ first = rb_ary_entry(args_ary,0);
2663
+
2664
+ if (len == 1 && (first == Qnil || TYPE(first) == T_FIXNUM || TYPE(first) == T_BIGNUM)) {
2665
+ return first == Qnil ? 0 : NUM2LONG(first);
2666
+ }
2667
+
2668
+ // we could have multiple values, but they should be symbols
2669
+ // rb_obj_as_string always yields a String, even if to_s misbehaves;
2670
+ // RSTRING_PTR on a raw rb_funcall result would crash if #to_s returned
2671
+ // a non-String (e.g. a Fixnum, whose VALUE isn't a real pointer).
2672
+ for( i = 0; i < len; ++i ) {
2673
+ VALUE node_str = rb_obj_as_string(rb_ary_entry(args_ary,i));
2674
+ node = StringValuePtr(node_str);
2675
+ mask |= CURL_HTTPAUTH_STR_TO_NUM(node);
2676
+ }
2677
+ return mask;
2678
+ }
2679
+
2555
2680
  /*
2556
2681
  * call-seq:
2557
2682
  * easy.http_auth_types = fixnum or nil => fixnum or nil
@@ -2561,37 +2686,14 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
2561
2686
  * +perform+ calls. This is a bitmap made by ORing together the
2562
2687
  * Curl::CURLAUTH constants.
2563
2688
  */
2564
- static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {//VALUE self, VALUE http_auth_types) {
2689
+ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {
2565
2690
  ruby_curl_easy *rbce;
2566
2691
  VALUE args_ary;
2567
- long i, len;
2568
- char* node = NULL;
2569
- long mask = 0;
2570
2692
 
2571
2693
  rb_scan_args(argc, argv, "*", &args_ary);
2572
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2694
+ rbce = ruby_curl_easy_get_handle(self);
2573
2695
 
2574
- len = RARRAY_LEN(args_ary);
2575
-
2576
- if (len == 1 && (rb_ary_entry(args_ary,0) == Qnil || TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM ||
2577
- TYPE(rb_ary_entry(args_ary,0)) == T_BIGNUM)) {
2578
- if (rb_ary_entry(args_ary,0) == Qnil) {
2579
- rbce->http_auth_types = 0;
2580
- }
2581
- else {
2582
- rbce->http_auth_types = NUM2LONG(rb_ary_entry(args_ary,0));
2583
- }
2584
- }
2585
- else {
2586
- // we could have multiple values, but they should be symbols
2587
- node = RSTRING_PTR(rb_funcall(rb_ary_entry(args_ary,0),rb_intern("to_s"),0));
2588
- mask = CURL_HTTPAUTH_STR_TO_NUM(node);
2589
- for( i = 1; i < len; ++i ) {
2590
- node = RSTRING_PTR(rb_funcall(rb_ary_entry(args_ary,i),rb_intern("to_s"),0));
2591
- mask |= CURL_HTTPAUTH_STR_TO_NUM(node);
2592
- }
2593
- rbce->http_auth_types = mask;
2594
- }
2696
+ rbce->http_auth_types = ruby_curl_easy_auth_types_to_mask(args_ary);
2595
2697
  return LONG2NUM(rbce->http_auth_types);
2596
2698
  }
2597
2699
 
@@ -2609,13 +2711,21 @@ static VALUE ruby_curl_easy_http_auth_types_get(VALUE self) {
2609
2711
  /*
2610
2712
  * call-seq:
2611
2713
  * easy.proxy_auth_types = fixnum or nil => fixnum or nil
2714
+ * easy.proxy_auth_types = [:basic,:digest,:digest_ie,:gssnegotiate, :ntlm, :any, :anysafe]
2612
2715
  *
2613
2716
  * Set the proxy authentication types that may be used for the following
2614
2717
  * +perform+ calls. This is a bitmap made by ORing together the
2615
2718
  * Curl::CURLAUTH constants.
2616
2719
  */
2617
- static VALUE ruby_curl_easy_proxy_auth_types_set(VALUE self, VALUE proxy_auth_types) {
2618
- CURB_IMMED_SETTER(ruby_curl_easy, proxy_auth_types, 0);
2720
+ static VALUE ruby_curl_easy_proxy_auth_types_set(int argc, VALUE *argv, VALUE self) {
2721
+ ruby_curl_easy *rbce;
2722
+ VALUE args_ary;
2723
+
2724
+ rb_scan_args(argc, argv, "*", &args_ary);
2725
+ rbce = ruby_curl_easy_get_handle(self);
2726
+
2727
+ rbce->proxy_auth_types = ruby_curl_easy_auth_types_to_mask(args_ary);
2728
+ return LONG2NUM(rbce->proxy_auth_types);
2619
2729
  }
2620
2730
 
2621
2731
  /*
@@ -2674,7 +2784,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
2674
2784
  */
2675
2785
  static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
2676
2786
  ruby_curl_easy *rbce;
2677
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2787
+ rbce = ruby_curl_easy_get_handle(self);
2678
2788
 
2679
2789
  if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
2680
2790
  rbce->timeout_ms = 0;
@@ -2697,7 +2807,7 @@ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
2697
2807
  */
2698
2808
  static VALUE ruby_curl_easy_timeout_get(VALUE self) {
2699
2809
  ruby_curl_easy *rbce;
2700
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2810
+ rbce = ruby_curl_easy_get_handle(self);
2701
2811
  return DBL2NUM(rbce->timeout_ms / 1000.0);
2702
2812
  }
2703
2813
 
@@ -2715,7 +2825,7 @@ static VALUE ruby_curl_easy_timeout_get(VALUE self) {
2715
2825
  */
2716
2826
  static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
2717
2827
  ruby_curl_easy *rbce;
2718
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2828
+ rbce = ruby_curl_easy_get_handle(self);
2719
2829
 
2720
2830
  if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
2721
2831
  rbce->timeout_ms = 0;
@@ -2735,7 +2845,7 @@ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
2735
2845
  */
2736
2846
  static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
2737
2847
  ruby_curl_easy *rbce;
2738
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2848
+ rbce = ruby_curl_easy_get_handle(self);
2739
2849
  return LONG2NUM(rbce->timeout_ms);
2740
2850
  }
2741
2851
 
@@ -3208,7 +3318,7 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
3208
3318
  */
3209
3319
  static VALUE ruby_curl_easy_autoreferer_set(VALUE self, VALUE autoreferer) {
3210
3320
  ruby_curl_easy *rbce;
3211
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3321
+ rbce = ruby_curl_easy_get_handle(self);
3212
3322
 
3213
3323
  if (Qtrue == autoreferer) {
3214
3324
  curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 1);
@@ -3365,7 +3475,7 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
3365
3475
  static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
3366
3476
  ruby_curl_easy *rbce;
3367
3477
  unsigned short rm;
3368
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3478
+ rbce = ruby_curl_easy_get_handle(self);
3369
3479
 
3370
3480
  rm = rbce->resolve_mode;
3371
3481
 
@@ -3397,7 +3507,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
3397
3507
  } else {
3398
3508
  ruby_curl_easy *rbce;
3399
3509
  ID resolve_mode_id;
3400
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3510
+ rbce = ruby_curl_easy_get_handle(self);
3401
3511
 
3402
3512
  resolve_mode_id = rb_to_id(resolve_mode);
3403
3513
 
@@ -3426,7 +3536,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
3426
3536
  */
3427
3537
  static VALUE ruby_curl_easy_network_policy_get(VALUE self) {
3428
3538
  ruby_curl_easy *rbce;
3429
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3539
+ rbce = ruby_curl_easy_get_handle(self);
3430
3540
 
3431
3541
  switch (rbce->network_policy) {
3432
3542
  case CURB_NETWORK_POLICY_PUBLIC:
@@ -3450,7 +3560,7 @@ static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy)
3450
3560
  ruby_curl_easy *rbce;
3451
3561
  ID network_policy_id;
3452
3562
 
3453
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3563
+ rbce = ruby_curl_easy_get_handle(self);
3454
3564
 
3455
3565
  if (NIL_P(network_policy)) {
3456
3566
  rbce->network_policy = CURB_NETWORK_POLICY_NONE;
@@ -3488,7 +3598,7 @@ static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy)
3488
3598
  */
3489
3599
  static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
3490
3600
  ruby_curl_easy *rbce;
3491
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3601
+ rbce = ruby_curl_easy_get_handle(self);
3492
3602
 
3493
3603
  if (rbce->unsafe_destination_blocked && rbce->unsafe_destination_error[0]) {
3494
3604
  return rb_str_new2(rbce->unsafe_destination_error);
@@ -3506,7 +3616,7 @@ static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
3506
3616
  */
3507
3617
  static VALUE ruby_curl_easy_unix_socket_path_get(VALUE self) {
3508
3618
  ruby_curl_easy *rbce;
3509
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3619
+ rbce = ruby_curl_easy_get_handle(self);
3510
3620
 
3511
3621
  return rb_easy_get("unix_socket_path");
3512
3622
  }
@@ -3525,7 +3635,7 @@ static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
3525
3635
  ruby_curl_easy *rbce;
3526
3636
  long http_version;
3527
3637
 
3528
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3638
+ rbce = ruby_curl_easy_get_handle(self);
3529
3639
 
3530
3640
  if (NIL_P(version)) {
3531
3641
  http_version = CURL_HTTP_VERSION_NONE;
@@ -3547,7 +3657,7 @@ static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
3547
3657
  static VALUE ruby_curl_easy_http_version_get(VALUE self) {
3548
3658
  ruby_curl_easy *rbce;
3549
3659
 
3550
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3660
+ rbce = ruby_curl_easy_get_handle(self);
3551
3661
 
3552
3662
  return LONG2NUM(rbce->http_version);
3553
3663
  }
@@ -4330,7 +4440,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
4330
4440
  static VALUE ruby_curl_easy_setup_self(VALUE self) {
4331
4441
  ruby_curl_easy *rbce;
4332
4442
 
4333
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4443
+ rbce = ruby_curl_easy_get_handle(self);
4334
4444
  ruby_curl_easy_setup(rbce);
4335
4445
 
4336
4446
  return self;
@@ -4436,7 +4546,7 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
4436
4546
  CURL *curl;
4437
4547
  VALUE retval;
4438
4548
 
4439
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4549
+ rbce = ruby_curl_easy_get_handle(self);
4440
4550
  curl = rbce->curl;
4441
4551
 
4442
4552
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
@@ -4501,6 +4611,8 @@ struct easy_form_perform_args {
4501
4611
  struct curl_httppost *last;
4502
4612
  int clear_customrequest;
4503
4613
  int form_set_on_curl;
4614
+ ruby_curl_form_string *strings;
4615
+ ruby_curl_easy *rbce;
4504
4616
  };
4505
4617
 
4506
4618
  struct easy_join_args {
@@ -4522,15 +4634,16 @@ static VALUE join_easy_arguments(ruby_curl_easy *rbce, VALUE args_ary) {
4522
4634
 
4523
4635
  static void append_multipart_form_argument(VALUE arg,
4524
4636
  struct curl_httppost **first,
4525
- struct curl_httppost **last) {
4637
+ struct curl_httppost **last,
4638
+ ruby_curl_form_string **strings) {
4526
4639
  if (rb_obj_is_instance_of(arg, cCurlPostField)) {
4527
- append_to_form(arg, first, last);
4640
+ append_to_form(arg, first, last, strings);
4528
4641
  } else if (rb_type(arg) == T_ARRAY) {
4529
4642
  long j, argv_len = RARRAY_LEN(arg);
4530
4643
  for (j = 0; j < argv_len; ++j) {
4531
4644
  VALUE field = rb_ary_entry(arg, j);
4532
4645
  if (rb_obj_is_instance_of(field, cCurlPostField)) {
4533
- append_to_form(field, first, last);
4646
+ append_to_form(field, first, last, strings);
4534
4647
  } else {
4535
4648
  rb_raise(eCurlErrInvalidPostField,
4536
4649
  "You must use PostFields only with multipart form posts");
@@ -4545,23 +4658,35 @@ static void append_multipart_form_argument(VALUE arg,
4545
4658
  static VALUE build_and_perform_multipart_form(VALUE argp) {
4546
4659
  struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
4547
4660
  int i;
4661
+ ruby_curl_easy *rbce;
4662
+
4663
+ rbce = ruby_curl_easy_get_handle(args->self);
4664
+ args->rbce = rbce;
4665
+ ruby_curl_easy_enter_native(rbce);
4666
+ rbce->multipart_building = 1;
4548
4667
 
4549
4668
  for (i = 0; i < args->argc; i++) {
4550
- append_multipart_form_argument(args->argv[i], &args->first, &args->last);
4669
+ append_multipart_form_argument(args->argv[i], &args->first, &args->last, &args->strings);
4551
4670
  }
4552
4671
 
4553
4672
  curl_easy_setopt(args->curl, CURLOPT_POST, 0);
4554
4673
  curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, args->first);
4555
4674
  args->form_set_on_curl = 1;
4675
+ rbce->multipart_form_active = 1;
4556
4676
 
4677
+ rbce->multipart_building = 0;
4557
4678
  return call_easy_perform(args->self);
4558
4679
  }
4559
4680
 
4560
4681
  static VALUE ensure_free_form_post(VALUE argp) {
4561
4682
  struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
4683
+ if (args->rbce) args->rbce->multipart_building = 0;
4562
4684
  if (args->curl) {
4563
4685
  if (args->form_set_on_curl) {
4686
+ ruby_curl_easy *rbce;
4687
+ rbce = ruby_curl_easy_get_handle(args->self);
4564
4688
  curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, NULL);
4689
+ rbce->multipart_form_active = 0;
4565
4690
  }
4566
4691
  if (args->clear_customrequest) {
4567
4692
  curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
@@ -4572,6 +4697,9 @@ static VALUE ensure_free_form_post(VALUE argp) {
4572
4697
  args->first = NULL;
4573
4698
  }
4574
4699
  args->last = NULL;
4700
+ free_form_strings(args->strings);
4701
+ args->strings = NULL;
4702
+ if (args->rbce) ruby_curl_easy_leave_native((VALUE)args->rbce);
4575
4703
  return Qnil;
4576
4704
  }
4577
4705
 
@@ -4606,7 +4734,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
4606
4734
 
4607
4735
  rb_scan_args(argc, argv, "*", &args_ary);
4608
4736
 
4609
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4737
+ rbce = ruby_curl_easy_get_handle(self);
4610
4738
  curl = rbce->curl;
4611
4739
 
4612
4740
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
@@ -4615,7 +4743,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
4615
4743
 
4616
4744
  if (rbce->multipart_form_post) {
4617
4745
  VALUE ret;
4618
- struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0 };
4746
+ struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0, NULL, NULL };
4619
4747
  ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
4620
4748
 
4621
4749
  return ret;
@@ -4665,7 +4793,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
4665
4793
  VALUE args_ary;
4666
4794
 
4667
4795
  rb_scan_args(argc, argv, "*", &args_ary);
4668
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4796
+ rbce = ruby_curl_easy_get_handle(self);
4669
4797
  curl = rbce->curl;
4670
4798
 
4671
4799
  /* Clear the error buffer */
@@ -4676,7 +4804,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
4676
4804
 
4677
4805
  if (rbce->multipart_form_post) {
4678
4806
  VALUE ret;
4679
- struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
4807
+ struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0, NULL, NULL };
4680
4808
  ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
4681
4809
  return ret;
4682
4810
  } else {
@@ -4714,7 +4842,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
4714
4842
  VALUE args_ary;
4715
4843
 
4716
4844
  rb_scan_args(argc, argv, "*", &args_ary);
4717
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4845
+ rbce = ruby_curl_easy_get_handle(self);
4718
4846
  curl = rbce->curl;
4719
4847
 
4720
4848
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
@@ -4734,7 +4862,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
4734
4862
  /* Otherwise, if multipart_form_post is true, use multipart logic */
4735
4863
  else if (rbce->multipart_form_post) {
4736
4864
  VALUE ret;
4737
- struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
4865
+ struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0, NULL, NULL };
4738
4866
  ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
4739
4867
  return ret;
4740
4868
  }
@@ -4781,7 +4909,7 @@ static VALUE ruby_curl_easy_max_body_bytes_set(VALUE self, VALUE val) {
4781
4909
  ruby_curl_easy *rbce;
4782
4910
  long long limit;
4783
4911
 
4784
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4912
+ rbce = ruby_curl_easy_get_handle(self);
4785
4913
 
4786
4914
  if (NIL_P(val)) {
4787
4915
  rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
@@ -4836,10 +4964,10 @@ static VALUE ruby_curl_easy_header_str_get(VALUE self) {
4836
4964
  */
4837
4965
  static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
4838
4966
  ruby_curl_easy *rbce;
4839
- char* url;
4967
+ char* url = NULL;
4840
4968
 
4841
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4842
- curl_easy_getinfo(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
4969
+ rbce = ruby_curl_easy_get_handle(self);
4970
+ CURB_GETINFO(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
4843
4971
 
4844
4972
  if (url && url[0]) { // curl returns empty string if none
4845
4973
  return rb_str_new2(url);
@@ -4859,14 +4987,14 @@ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
4859
4987
  */
4860
4988
  static VALUE ruby_curl_easy_response_code_get(VALUE self) {
4861
4989
  ruby_curl_easy *rbce;
4862
- long code;
4990
+ long code = 0;
4863
4991
 
4864
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4992
+ rbce = ruby_curl_easy_get_handle(self);
4865
4993
  #ifdef HAVE_CURLINFO_RESPONSE_CODE
4866
- curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
4994
+ CURB_GETINFO(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
4867
4995
  #else
4868
4996
  // old libcurl
4869
- curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CODE, &code);
4997
+ CURB_GETINFO(rbce->curl, CURLINFO_HTTP_CODE, &code);
4870
4998
  #endif
4871
4999
 
4872
5000
  return LONG2NUM(code);
@@ -4883,10 +5011,10 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
4883
5011
  */
4884
5012
  static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
4885
5013
  ruby_curl_easy *rbce;
4886
- char* ip;
5014
+ char* ip = NULL;
4887
5015
 
4888
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4889
- curl_easy_getinfo(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
5016
+ rbce = ruby_curl_easy_get_handle(self);
5017
+ CURB_GETINFO(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
4890
5018
 
4891
5019
  if (ip && ip[0]) { // curl returns empty string if none
4892
5020
  return rb_str_new2(ip);
@@ -4904,10 +5032,10 @@ static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
4904
5032
  */
4905
5033
  static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
4906
5034
  ruby_curl_easy *rbce;
4907
- long code;
5035
+ long code = 0;
4908
5036
 
4909
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4910
- curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
5037
+ rbce = ruby_curl_easy_get_handle(self);
5038
+ CURB_GETINFO(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
4911
5039
 
4912
5040
  return LONG2NUM(code);
4913
5041
  }
@@ -4932,10 +5060,10 @@ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
4932
5060
  static VALUE ruby_curl_easy_file_time_get(VALUE self) {
4933
5061
  #ifdef HAVE_CURLINFO_FILETIME
4934
5062
  ruby_curl_easy *rbce;
4935
- long time;
5063
+ long time = 0;
4936
5064
 
4937
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4938
- curl_easy_getinfo(rbce->curl, CURLINFO_FILETIME, &time);
5065
+ rbce = ruby_curl_easy_get_handle(self);
5066
+ CURB_GETINFO(rbce->curl, CURLINFO_FILETIME, &time);
4939
5067
 
4940
5068
  return LONG2NUM(time);
4941
5069
  #else
@@ -4953,10 +5081,10 @@ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
4953
5081
  */
4954
5082
  static VALUE ruby_curl_easy_total_time_get(VALUE self) {
4955
5083
  ruby_curl_easy *rbce;
4956
- double time;
5084
+ double time = 0;
4957
5085
 
4958
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4959
- curl_easy_getinfo(rbce->curl, CURLINFO_TOTAL_TIME, &time);
5086
+ rbce = ruby_curl_easy_get_handle(self);
5087
+ CURB_GETINFO(rbce->curl, CURLINFO_TOTAL_TIME, &time);
4960
5088
 
4961
5089
  return rb_float_new(time);
4962
5090
  }
@@ -4970,10 +5098,10 @@ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
4970
5098
  */
4971
5099
  static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
4972
5100
  ruby_curl_easy *rbce;
4973
- double time;
5101
+ double time = 0;
4974
5102
 
4975
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4976
- curl_easy_getinfo(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
5103
+ rbce = ruby_curl_easy_get_handle(self);
5104
+ CURB_GETINFO(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
4977
5105
 
4978
5106
  return rb_float_new(time);
4979
5107
  }
@@ -4987,10 +5115,10 @@ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
4987
5115
  */
4988
5116
  static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
4989
5117
  ruby_curl_easy *rbce;
4990
- double time;
5118
+ double time = 0;
4991
5119
 
4992
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4993
- curl_easy_getinfo(rbce->curl, CURLINFO_CONNECT_TIME, &time);
5120
+ rbce = ruby_curl_easy_get_handle(self);
5121
+ CURB_GETINFO(rbce->curl, CURLINFO_CONNECT_TIME, &time);
4994
5122
 
4995
5123
  return rb_float_new(time);
4996
5124
  }
@@ -5008,10 +5136,10 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
5008
5136
  #if defined(HAVE_CURLINFO_APPCONNECT_TIME)
5009
5137
  static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
5010
5138
  ruby_curl_easy *rbce;
5011
- double time;
5139
+ double time = 0;
5012
5140
 
5013
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5014
- curl_easy_getinfo(rbce->curl, CURLINFO_APPCONNECT_TIME, &time);
5141
+ rbce = ruby_curl_easy_get_handle(self);
5142
+ CURB_GETINFO(rbce->curl, CURLINFO_APPCONNECT_TIME, &time);
5015
5143
 
5016
5144
  return rb_float_new(time);
5017
5145
  }
@@ -5029,10 +5157,10 @@ static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
5029
5157
  */
5030
5158
  static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
5031
5159
  ruby_curl_easy *rbce;
5032
- double time;
5160
+ double time = 0;
5033
5161
 
5034
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5035
- curl_easy_getinfo(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
5162
+ rbce = ruby_curl_easy_get_handle(self);
5163
+ CURB_GETINFO(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
5036
5164
 
5037
5165
  return rb_float_new(time);
5038
5166
  }
@@ -5047,10 +5175,10 @@ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
5047
5175
  */
5048
5176
  static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
5049
5177
  ruby_curl_easy *rbce;
5050
- double time;
5178
+ double time = 0;
5051
5179
 
5052
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5053
- curl_easy_getinfo(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
5180
+ rbce = ruby_curl_easy_get_handle(self);
5181
+ CURB_GETINFO(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
5054
5182
 
5055
5183
  return rb_float_new(time);
5056
5184
  }
@@ -5069,10 +5197,10 @@ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
5069
5197
  static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
5070
5198
  #ifdef HAVE_CURLINFO_REDIRECT_TIME
5071
5199
  ruby_curl_easy *rbce;
5072
- double time;
5200
+ double time = 0;
5073
5201
 
5074
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5075
- curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
5202
+ rbce = ruby_curl_easy_get_handle(self);
5203
+ CURB_GETINFO(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
5076
5204
 
5077
5205
  return rb_float_new(time);
5078
5206
  #else
@@ -5092,10 +5220,10 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
5092
5220
  static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
5093
5221
  #ifdef HAVE_CURLINFO_REDIRECT_COUNT
5094
5222
  ruby_curl_easy *rbce;
5095
- long count;
5223
+ long count = 0;
5096
5224
 
5097
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5098
- curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
5225
+ rbce = ruby_curl_easy_get_handle(self);
5226
+ CURB_GETINFO(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
5099
5227
 
5100
5228
  return LONG2NUM(count);
5101
5229
  #else
@@ -5117,10 +5245,10 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
5117
5245
  static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
5118
5246
  #ifdef HAVE_CURLINFO_REDIRECT_URL
5119
5247
  ruby_curl_easy *rbce;
5120
- char* url;
5248
+ char* url = NULL;
5121
5249
 
5122
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5123
- curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
5250
+ rbce = ruby_curl_easy_get_handle(self);
5251
+ CURB_GETINFO(rbce->curl, CURLINFO_REDIRECT_URL, &url);
5124
5252
 
5125
5253
  if (url && url[0]) { // curl returns empty string if none
5126
5254
  return rb_str_new2(url);
@@ -5144,15 +5272,15 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
5144
5272
  */
5145
5273
  static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
5146
5274
  ruby_curl_easy *rbce;
5147
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5275
+ rbce = ruby_curl_easy_get_handle(self);
5148
5276
 
5149
5277
  #ifdef HAVE_CURLINFO_SIZE_UPLOAD_T
5150
- curl_off_t bytes;
5151
- curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD_T, &bytes);
5278
+ curl_off_t bytes = 0;
5279
+ CURB_GETINFO(rbce->curl, CURLINFO_SIZE_UPLOAD_T, &bytes);
5152
5280
  return LL2NUM(bytes);
5153
5281
  #else
5154
- double bytes;
5155
- curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
5282
+ double bytes = 0;
5283
+ CURB_GETINFO(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
5156
5284
  return rb_float_new(bytes);
5157
5285
  #endif
5158
5286
  }
@@ -5166,15 +5294,15 @@ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
5166
5294
  */
5167
5295
  static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
5168
5296
  ruby_curl_easy *rbce;
5169
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5297
+ rbce = ruby_curl_easy_get_handle(self);
5170
5298
 
5171
5299
  #ifdef HAVE_CURLINFO_SIZE_DOWNLOAD_T
5172
- curl_off_t bytes;
5173
- curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD_T, &bytes);
5300
+ curl_off_t bytes = 0;
5301
+ CURB_GETINFO(rbce->curl, CURLINFO_SIZE_DOWNLOAD_T, &bytes);
5174
5302
  return LL2NUM(bytes);
5175
5303
  #else
5176
- double bytes;
5177
- curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
5304
+ double bytes = 0;
5305
+ CURB_GETINFO(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
5178
5306
  return rb_float_new(bytes);
5179
5307
  #endif
5180
5308
  }
@@ -5188,15 +5316,15 @@ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
5188
5316
  */
5189
5317
  static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
5190
5318
  ruby_curl_easy *rbce;
5191
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5319
+ rbce = ruby_curl_easy_get_handle(self);
5192
5320
 
5193
5321
  #ifdef HAVE_CURLINFO_SPEED_UPLOAD_T
5194
- curl_off_t bytes;
5195
- curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD_T, &bytes);
5322
+ curl_off_t bytes = 0;
5323
+ CURB_GETINFO(rbce->curl, CURLINFO_SPEED_UPLOAD_T, &bytes);
5196
5324
  return LL2NUM(bytes);
5197
5325
  #else
5198
- double bytes;
5199
- curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
5326
+ double bytes = 0;
5327
+ CURB_GETINFO(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
5200
5328
  return rb_float_new(bytes);
5201
5329
  #endif
5202
5330
  }
@@ -5210,15 +5338,15 @@ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
5210
5338
  */
5211
5339
  static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
5212
5340
  ruby_curl_easy *rbce;
5213
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5341
+ rbce = ruby_curl_easy_get_handle(self);
5214
5342
 
5215
5343
  #ifdef HAVE_CURLINFO_SPEED_DOWNLOAD_T
5216
- curl_off_t bytes;
5217
- curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD_T, &bytes);
5344
+ curl_off_t bytes = 0;
5345
+ CURB_GETINFO(rbce->curl, CURLINFO_SPEED_DOWNLOAD_T, &bytes);
5218
5346
  return LL2NUM(bytes);
5219
5347
  #else
5220
- double bytes;
5221
- curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
5348
+ double bytes = 0;
5349
+ CURB_GETINFO(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
5222
5350
  return rb_float_new(bytes);
5223
5351
  #endif
5224
5352
  }
@@ -5232,10 +5360,10 @@ static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
5232
5360
  */
5233
5361
  static VALUE ruby_curl_easy_header_size_get(VALUE self) {
5234
5362
  ruby_curl_easy *rbce;
5235
- long size;
5363
+ long size = 0;
5236
5364
 
5237
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5238
- curl_easy_getinfo(rbce->curl, CURLINFO_HEADER_SIZE, &size);
5365
+ rbce = ruby_curl_easy_get_handle(self);
5366
+ CURB_GETINFO(rbce->curl, CURLINFO_HEADER_SIZE, &size);
5239
5367
 
5240
5368
  return LONG2NUM(size);
5241
5369
  }
@@ -5250,10 +5378,10 @@ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
5250
5378
  */
5251
5379
  static VALUE ruby_curl_easy_request_size_get(VALUE self) {
5252
5380
  ruby_curl_easy *rbce;
5253
- long size;
5381
+ long size = 0;
5254
5382
 
5255
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5256
- curl_easy_getinfo(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
5383
+ rbce = ruby_curl_easy_get_handle(self);
5384
+ CURB_GETINFO(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
5257
5385
 
5258
5386
  return LONG2NUM(size);
5259
5387
  }
@@ -5267,10 +5395,10 @@ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
5267
5395
  */
5268
5396
  static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
5269
5397
  ruby_curl_easy *rbce;
5270
- long result;
5398
+ long result = 0;
5271
5399
 
5272
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5273
- curl_easy_getinfo(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
5400
+ rbce = ruby_curl_easy_get_handle(self);
5401
+ CURB_GETINFO(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
5274
5402
 
5275
5403
  return LONG2NUM(result);
5276
5404
  }
@@ -5292,15 +5420,15 @@ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done
5292
5420
  */
5293
5421
  static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
5294
5422
  ruby_curl_easy *rbce;
5295
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5423
+ rbce = ruby_curl_easy_get_handle(self);
5296
5424
 
5297
5425
  #ifdef HAVE_CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
5298
- curl_off_t bytes;
5299
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &bytes);
5426
+ curl_off_t bytes = 0;
5427
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &bytes);
5300
5428
  return LL2NUM(bytes);
5301
5429
  #else
5302
- double bytes;
5303
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
5430
+ double bytes = 0;
5431
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
5304
5432
  return rb_float_new(bytes);
5305
5433
  #endif
5306
5434
  }
@@ -5313,15 +5441,15 @@ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
5313
5441
  */
5314
5442
  static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
5315
5443
  ruby_curl_easy *rbce;
5316
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5444
+ rbce = ruby_curl_easy_get_handle(self);
5317
5445
 
5318
5446
  #ifdef HAVE_CURLINFO_CONTENT_LENGTH_UPLOAD_T
5319
- curl_off_t bytes;
5320
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &bytes);
5447
+ curl_off_t bytes = 0;
5448
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &bytes);
5321
5449
  return LL2NUM(bytes);
5322
5450
  #else
5323
- double bytes;
5324
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
5451
+ double bytes = 0;
5452
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
5325
5453
  return rb_float_new(bytes);
5326
5454
  #endif
5327
5455
  }
@@ -5337,10 +5465,10 @@ static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
5337
5465
  */
5338
5466
  static VALUE ruby_curl_easy_content_type_get(VALUE self) {
5339
5467
  ruby_curl_easy *rbce;
5340
- char* type;
5468
+ char* type = NULL;
5341
5469
 
5342
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5343
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
5470
+ rbce = ruby_curl_easy_get_handle(self);
5471
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
5344
5472
 
5345
5473
  if (type && type[0]) { // curl returns empty string if none
5346
5474
  return rb_str_new2(type);
@@ -5380,10 +5508,10 @@ Pass a pointer to a long to receive a bitmask indicating the authentication meth
5380
5508
  static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
5381
5509
  #ifdef HAVE_CURLINFO_OS_ERRNO
5382
5510
  ruby_curl_easy *rbce;
5383
- long result;
5511
+ long result = 0;
5384
5512
 
5385
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5386
- curl_easy_getinfo(rbce->curl, CURLINFO_OS_ERRNO, &result);
5513
+ rbce = ruby_curl_easy_get_handle(self);
5514
+ CURB_GETINFO(rbce->curl, CURLINFO_OS_ERRNO, &result);
5387
5515
 
5388
5516
  return LONG2NUM(result);
5389
5517
  #else
@@ -5409,10 +5537,10 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
5409
5537
  static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
5410
5538
  #ifdef HAVE_CURLINFO_NUM_CONNECTS
5411
5539
  ruby_curl_easy *rbce;
5412
- long result;
5540
+ long result = 0;
5413
5541
 
5414
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5415
- curl_easy_getinfo(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
5542
+ rbce = ruby_curl_easy_get_handle(self);
5543
+ CURB_GETINFO(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
5416
5544
 
5417
5545
  return LONG2NUM(result);
5418
5546
  #else
@@ -5444,12 +5572,12 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
5444
5572
  static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
5445
5573
  #ifdef HAVE_CURLINFO_COOKIELIST
5446
5574
  ruby_curl_easy *rbce;
5447
- struct curl_slist *cookies;
5575
+ struct curl_slist *cookies = NULL;
5448
5576
  struct curl_slist *cookie;
5449
5577
  VALUE rb_cookies;
5450
5578
 
5451
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5452
- curl_easy_getinfo(rbce->curl, CURLINFO_COOKIELIST, &cookies);
5579
+ rbce = ruby_curl_easy_get_handle(self);
5580
+ CURB_GETINFO(rbce->curl, CURLINFO_COOKIELIST, &cookies);
5453
5581
  if (!cookies)
5454
5582
  return Qnil;
5455
5583
  rb_cookies = rb_ary_new();
@@ -5488,8 +5616,8 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
5488
5616
  ruby_curl_easy *rbce;
5489
5617
  char* path = NULL;
5490
5618
 
5491
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5492
- curl_easy_getinfo(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
5619
+ rbce = ruby_curl_easy_get_handle(self);
5620
+ CURB_GETINFO(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
5493
5621
 
5494
5622
  if (path && path[0]) { // curl returns NULL or empty string if none
5495
5623
  return rb_str_new2(path);
@@ -5508,7 +5636,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
5508
5636
  */
5509
5637
  static VALUE ruby_curl_easy_multi_get(VALUE self) {
5510
5638
  ruby_curl_easy *rbce;
5511
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5639
+ rbce = ruby_curl_easy_get_handle(self);
5512
5640
  return rbce->multi;
5513
5641
  }
5514
5642
 
@@ -5521,7 +5649,7 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
5521
5649
  VALUE old_multi;
5522
5650
  ruby_curl_multi *old_rbcm;
5523
5651
  CURLMcode result;
5524
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5652
+ rbce = ruby_curl_easy_get_handle(self);
5525
5653
 
5526
5654
  if (!NIL_P(multi) && rb_obj_is_kind_of(multi, cCurlMulti) != Qtrue) {
5527
5655
  rb_raise(rb_eTypeError, "expected Curl::Multi or nil");
@@ -5550,7 +5678,7 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
5550
5678
  */
5551
5679
  static VALUE ruby_curl_easy_last_result(VALUE self) {
5552
5680
  ruby_curl_easy *rbce;
5553
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5681
+ rbce = ruby_curl_easy_get_handle(self);
5554
5682
  return LONG2NUM(rbce->last_result);
5555
5683
  }
5556
5684
 
@@ -5560,7 +5688,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
5560
5688
  */
5561
5689
  static VALUE ruby_curl_easy_last_error(VALUE self) {
5562
5690
  ruby_curl_easy *rbce;
5563
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5691
+ rbce = ruby_curl_easy_get_handle(self);
5564
5692
 
5565
5693
  if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
5566
5694
  return rb_str_new2(rbce->err_buf);
@@ -5598,7 +5726,8 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
5598
5726
  long option = NUM2LONG(opt);
5599
5727
  rb_io_t *open_f_ptr;
5600
5728
 
5601
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5729
+ rbce = ruby_curl_easy_get_handle(self);
5730
+ ruby_curl_easy_check_idle(rbce);
5602
5731
 
5603
5732
  switch (option) {
5604
5733
  /* BEHAVIOR OPTIONS */
@@ -6050,6 +6179,28 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
6050
6179
 
6051
6180
  /* ================== ESCAPING FUNCS ==============*/
6052
6181
 
6182
+ struct curl_string_result {
6183
+ char *data;
6184
+ long length;
6185
+ };
6186
+
6187
+ static VALUE curl_string_result_body(VALUE argp) {
6188
+ struct curl_string_result *args = (struct curl_string_result *)argp;
6189
+ return rb_str_new(args->data, args->length);
6190
+ }
6191
+
6192
+ static VALUE curl_string_result_free(VALUE argp) {
6193
+ struct curl_string_result *args = (struct curl_string_result *)argp;
6194
+ curl_free(args->data);
6195
+ return Qnil;
6196
+ }
6197
+
6198
+ static VALUE curl_string_result_to_ruby(char *data, long length) {
6199
+ struct curl_string_result args = { data, length };
6200
+ return rb_ensure(curl_string_result_body, (VALUE)&args,
6201
+ curl_string_result_free, (VALUE)&args);
6202
+ }
6203
+
6053
6204
  /*
6054
6205
  * call-seq:
6055
6206
  * easy.escape("some text") => "some%20text"
@@ -6062,13 +6213,13 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
6062
6213
  static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
6063
6214
  ruby_curl_easy *rbce;
6064
6215
  char *result;
6065
- VALUE rresult;
6066
6216
  VALUE str = svalue;
6067
6217
 
6068
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
6218
+ rbce = ruby_curl_easy_get_handle(self);
6069
6219
 
6070
- /* NOTE: make sure the value is a string, if not call to_s */
6071
- if( rb_type(str) != T_STRING ) { str = rb_funcall(str,rb_intern("to_s"),0); }
6220
+ /* NOTE: make sure the value is a string; rb_obj_as_string always yields a
6221
+ * String, even if the object's to_s misbehaves and returns a non-String. */
6222
+ if( rb_type(str) != T_STRING ) { str = rb_obj_as_string(str); }
6072
6223
 
6073
6224
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
6074
6225
  result = (char*)curl_easy_escape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str));
@@ -6076,10 +6227,8 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
6076
6227
  result = (char*)curl_escape(StringValuePtr(str), (int)RSTRING_LEN(str));
6077
6228
  #endif
6078
6229
 
6079
- rresult = rb_str_new2(result);
6080
- curl_free(result);
6081
-
6082
- return rresult;
6230
+ if (!result) rb_raise(eCurlErrError, "Failed to URL-encode string");
6231
+ return curl_string_result_to_ruby(result, (long)strlen(result));
6083
6232
  }
6084
6233
 
6085
6234
  /*
@@ -6094,21 +6243,25 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
6094
6243
  ruby_curl_easy *rbce;
6095
6244
  int rlen;
6096
6245
  char *result;
6097
- VALUE rresult;
6098
6246
 
6099
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
6247
+ rbce = ruby_curl_easy_get_handle(self);
6248
+
6249
+ /* Coerce as its own statement before use below - StringValuePtr and
6250
+ * RSTRING_LEN are sibling args to the same call and C does not guarantee
6251
+ * left-to-right evaluation order between them. */
6252
+ StringValue(str);
6100
6253
 
6101
6254
  #if (LIBCURL_VERSION_NUM >= 0x070f04)
6102
6255
  result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
6103
6256
  #else
6104
6257
  result = (char*)curl_unescape(StringValuePtr(str), (int)RSTRING_LEN(str));
6105
- rlen = strlen(result);
6106
6258
  #endif
6107
6259
 
6108
- rresult = rb_str_new(result, rlen);
6109
- curl_free(result);
6110
-
6111
- return rresult;
6260
+ if (!result) rb_raise(eCurlErrError, "Failed to URL-decode string");
6261
+ #if (LIBCURL_VERSION_NUM < 0x070f04)
6262
+ rlen = (int)strlen(result);
6263
+ #endif
6264
+ return curl_string_result_to_ruby(result, rlen);
6112
6265
  }
6113
6266
 
6114
6267
 
@@ -6132,7 +6285,7 @@ void init_curb_easy() {
6132
6285
  idNetworkPolicyNone = rb_intern("none");
6133
6286
  idNetworkPolicyPublic = rb_intern("public");
6134
6287
 
6135
- rbstrAmp = rb_str_new2("&");
6288
+ rbstrAmp = rb_obj_freeze(rb_str_new2("&"));
6136
6289
  rb_global_variable(&rbstrAmp);
6137
6290
 
6138
6291
  cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
@@ -6203,7 +6356,7 @@ void init_curb_easy() {
6203
6356
  rb_define_method(cCurlEasy, "proxy_type", ruby_curl_easy_proxy_type_get, 0);
6204
6357
  rb_define_method(cCurlEasy, "http_auth_types=", ruby_curl_easy_http_auth_types_set, -1);
6205
6358
  rb_define_method(cCurlEasy, "http_auth_types", ruby_curl_easy_http_auth_types_get, 0);
6206
- rb_define_method(cCurlEasy, "proxy_auth_types=", ruby_curl_easy_proxy_auth_types_set, 1);
6359
+ rb_define_method(cCurlEasy, "proxy_auth_types=", ruby_curl_easy_proxy_auth_types_set, -1);
6207
6360
  rb_define_method(cCurlEasy, "proxy_auth_types", ruby_curl_easy_proxy_auth_types_get, 0);
6208
6361
  rb_define_method(cCurlEasy, "max_redirects=", ruby_curl_easy_max_redirects_set, 1);
6209
6362
  rb_define_method(cCurlEasy, "max_redirects", ruby_curl_easy_max_redirects_get, 0);