curb 1.4.0 → 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
@@ -747,7 +747,7 @@ VALUE rb_curl_easy_take_callback_error(ruby_curl_easy *rbce) {
747
747
  static VALUE ruby_curl_easy_take_callback_error(VALUE self) {
748
748
  ruby_curl_easy *rbce = NULL;
749
749
 
750
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
750
+ rbce = ruby_curl_easy_get_handle(self);
751
751
  return rb_curl_easy_take_callback_error(rbce);
752
752
  }
753
753
 
@@ -1303,6 +1303,19 @@ static ruby_curl_multi *ruby_curl_multi_pointer_if_compatible(VALUE multi_val) {
1303
1303
  #endif
1304
1304
  }
1305
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
+
1306
1319
  static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
1307
1320
  if (!rbce) {
1308
1321
  return;
@@ -1319,10 +1332,7 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
1319
1332
  * libcurl retaining a dangling pointer to a soon-to-be cleaned-up easy
1320
1333
  * handle. This path runs during GC, so it must not invoke Ruby APIs that
1321
1334
  * can allocate or raise. */
1322
- if (rbcm->handle && rbce->curl) {
1323
- curl_multi_remove_handle(rbcm->handle, rbce->curl);
1324
- }
1325
- rb_curl_multi_forget_easy(rbcm, rbce);
1335
+ rb_curl_multi_detach_easy(rbcm, rbce);
1326
1336
  }
1327
1337
  }
1328
1338
 
@@ -1396,6 +1406,39 @@ const rb_data_type_t ruby_curl_easy_data_type = {
1396
1406
  };
1397
1407
 
1398
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
+
1399
1442
  /* ================= ALLOC METHODS ====================*/
1400
1443
 
1401
1444
  static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
@@ -1451,6 +1494,8 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
1451
1494
  rbce->unrestricted_auth = 0;
1452
1495
  rbce->verbose = 0;
1453
1496
  rbce->multipart_form_post = 0;
1497
+ rbce->multipart_form_active = 0;
1498
+ rbce->multipart_building = 0;
1454
1499
  rbce->enable_cookies = 0;
1455
1500
  rbce->cookielist_engine_enabled = 0;
1456
1501
  rbce->ignore_content_length = 0;
@@ -1500,6 +1545,16 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
1500
1545
 
1501
1546
  TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1502
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
+
1503
1558
  /* handler */
1504
1559
  rbce->curl = curl_easy_init();
1505
1560
  if (!rbce->curl) {
@@ -1571,11 +1626,13 @@ static VALUE duplicate_upload(VALUE upload) {
1571
1626
  *
1572
1627
  * Clone this Curl::Easy instance, creating a new instance.
1573
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.
1574
1631
  */
1575
1632
  static VALUE ruby_curl_easy_clone(VALUE self) {
1576
1633
  ruby_curl_easy *rbce, *newrbce;
1577
1634
 
1578
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1635
+ rbce = ruby_curl_easy_get_handle(self);
1579
1636
 
1580
1637
  newrbce = ALLOC(ruby_curl_easy);
1581
1638
  if (!newrbce) {
@@ -1590,6 +1647,18 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
1590
1647
  free(newrbce);
1591
1648
  rb_raise(rb_eNoMemError, "Failed to duplicate Curl::Easy handle");
1592
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
+ }
1593
1662
  newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
1594
1663
  newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
1595
1664
  newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
@@ -1603,6 +1672,7 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
1603
1672
  /* A cloned easy should not retain ownership reference to the original multi. */
1604
1673
  newrbce->multi = Qnil;
1605
1674
  newrbce->callback_error = Qnil;
1675
+ newrbce->callback_active = 0;
1606
1676
  newrbce->unsafe_destination_blocked = 0;
1607
1677
  memset(newrbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
1608
1678
  newrbce->native_active = 0;
@@ -1648,7 +1718,7 @@ static VALUE ruby_curl_easy_close(VALUE self) {
1648
1718
  CURLcode ecode;
1649
1719
  ruby_curl_easy *rbce;
1650
1720
 
1651
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1721
+ rbce = ruby_curl_easy_get_handle(self);
1652
1722
 
1653
1723
  if (rbce->callback_active) {
1654
1724
  rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
@@ -1658,6 +1728,9 @@ static VALUE ruby_curl_easy_close(VALUE self) {
1658
1728
  rb_raise(rb_eRuntimeError, "Cannot close an active curl handle during native operation");
1659
1729
  }
1660
1730
 
1731
+ ruby_curl_easy_check_idle(rbce);
1732
+ ruby_curl_easy_detach(self, rbce);
1733
+
1661
1734
  ruby_curl_easy_free(rbce);
1662
1735
 
1663
1736
  /* reinit the handle */
@@ -1699,7 +1772,7 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
1699
1772
  CURLcode ecode;
1700
1773
  ruby_curl_easy *rbce;
1701
1774
  VALUE opts_dup;
1702
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1775
+ rbce = ruby_curl_easy_get_handle(self);
1703
1776
 
1704
1777
  if (rbce->callback_active) {
1705
1778
  rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
@@ -1709,6 +1782,9 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
1709
1782
  rb_raise(rb_eRuntimeError, "Cannot reset an active curl handle during native operation");
1710
1783
  }
1711
1784
 
1785
+ ruby_curl_easy_check_idle(rbce);
1786
+ ruby_curl_easy_detach(self, rbce);
1787
+
1712
1788
  opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
1713
1789
 
1714
1790
  ruby_curl_easy_cleanup(self, rbce);
@@ -1790,7 +1866,7 @@ static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
1790
1866
  static VALUE ruby_curl_easy_headers_get(VALUE self) {
1791
1867
  ruby_curl_easy *rbce;
1792
1868
  VALUE headers;
1793
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1869
+ rbce = ruby_curl_easy_get_handle(self);
1794
1870
  headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
1795
1871
  if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
1796
1872
  return headers;
@@ -1825,7 +1901,7 @@ static VALUE ruby_curl_easy_headers_get(VALUE self) {
1825
1901
  static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
1826
1902
  ruby_curl_easy *rbce;
1827
1903
  VALUE proxy_headers;
1828
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
1904
+ rbce = ruby_curl_easy_get_handle(self);
1829
1905
  proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
1830
1906
  if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
1831
1907
  return proxy_headers;
@@ -2075,7 +2151,7 @@ static VALUE ruby_curl_easy_post_body_set_with_mode_body(VALUE argp) {
2075
2151
  char *data;
2076
2152
  long len;
2077
2153
 
2078
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2154
+ rbce = ruby_curl_easy_get_handle(self);
2079
2155
 
2080
2156
  curl = rbce->curl;
2081
2157
 
@@ -2134,7 +2210,7 @@ static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body,
2134
2210
  ruby_curl_easy *rbce;
2135
2211
  struct post_body_set_args args = { self, post_body, force_http_get_on_nil };
2136
2212
 
2137
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2213
+ rbce = ruby_curl_easy_get_handle(self);
2138
2214
  ruby_curl_easy_enter_native(rbce);
2139
2215
 
2140
2216
  return rb_ensure(ruby_curl_easy_post_body_set_with_mode_body, (VALUE)&args,
@@ -2171,7 +2247,7 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
2171
2247
  VALUE headers;
2172
2248
  VALUE infile_size = Qnil;
2173
2249
 
2174
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2250
+ rbce = ruby_curl_easy_get_handle(self);
2175
2251
 
2176
2252
  /*
2177
2253
  * Validate and prepare Ruby-visible state before mutating the CURL handle.
@@ -2356,7 +2432,7 @@ static VALUE ruby_curl_easy_dns_servers_get(VALUE self) {
2356
2432
  static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
2357
2433
  ruby_curl_easy *rbce;
2358
2434
 
2359
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2435
+ rbce = ruby_curl_easy_get_handle(self);
2360
2436
  rbce->allow_unix_socket = RTEST(allow) ? 1 : 0;
2361
2437
 
2362
2438
  return allow;
@@ -2365,7 +2441,7 @@ static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
2365
2441
  static VALUE ruby_curl_easy_allow_proxy_set(VALUE self, VALUE allow) {
2366
2442
  ruby_curl_easy *rbce;
2367
2443
 
2368
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2444
+ rbce = ruby_curl_easy_get_handle(self);
2369
2445
  rbce->allow_proxy = RTEST(allow) ? 1 : 0;
2370
2446
 
2371
2447
  return allow;
@@ -2384,7 +2460,7 @@ static VALUE ruby_curl_easy_allowed_cidrs_set(VALUE self, VALUE cidrs) {
2384
2460
  VALUE normalized;
2385
2461
  VALUE stored;
2386
2462
 
2387
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2463
+ rbce = ruby_curl_easy_get_handle(self);
2388
2464
  normalized = curb_normalize_cidr_list(cidrs);
2389
2465
  stored = curb_dup_string_array(normalized);
2390
2466
  rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_cidrs"), stored);
@@ -2405,7 +2481,7 @@ static VALUE ruby_curl_easy_allowed_cidrs_get(VALUE self) {
2405
2481
  ruby_curl_easy *rbce;
2406
2482
  VALUE cidrs;
2407
2483
 
2408
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2484
+ rbce = ruby_curl_easy_get_handle(self);
2409
2485
  cidrs = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_cidrs"));
2410
2486
 
2411
2487
  return curb_dup_string_array(cidrs);
@@ -2424,7 +2500,7 @@ static VALUE ruby_curl_easy_allowed_hosts_set(VALUE self, VALUE hosts) {
2424
2500
  VALUE normalized;
2425
2501
  VALUE stored;
2426
2502
 
2427
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2503
+ rbce = ruby_curl_easy_get_handle(self);
2428
2504
  normalized = curb_normalize_host_list(hosts);
2429
2505
  stored = curb_dup_string_array(normalized);
2430
2506
  rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_hosts"), stored);
@@ -2441,7 +2517,7 @@ static VALUE ruby_curl_easy_allowed_hosts_get(VALUE self) {
2441
2517
  ruby_curl_easy *rbce;
2442
2518
  VALUE hosts;
2443
2519
 
2444
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2520
+ rbce = ruby_curl_easy_get_handle(self);
2445
2521
  hosts = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_hosts"));
2446
2522
 
2447
2523
  return curb_dup_string_array(hosts);
@@ -2615,7 +2691,7 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
2615
2691
  VALUE args_ary;
2616
2692
 
2617
2693
  rb_scan_args(argc, argv, "*", &args_ary);
2618
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2694
+ rbce = ruby_curl_easy_get_handle(self);
2619
2695
 
2620
2696
  rbce->http_auth_types = ruby_curl_easy_auth_types_to_mask(args_ary);
2621
2697
  return LONG2NUM(rbce->http_auth_types);
@@ -2646,7 +2722,7 @@ static VALUE ruby_curl_easy_proxy_auth_types_set(int argc, VALUE *argv, VALUE se
2646
2722
  VALUE args_ary;
2647
2723
 
2648
2724
  rb_scan_args(argc, argv, "*", &args_ary);
2649
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2725
+ rbce = ruby_curl_easy_get_handle(self);
2650
2726
 
2651
2727
  rbce->proxy_auth_types = ruby_curl_easy_auth_types_to_mask(args_ary);
2652
2728
  return LONG2NUM(rbce->proxy_auth_types);
@@ -2708,7 +2784,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
2708
2784
  */
2709
2785
  static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
2710
2786
  ruby_curl_easy *rbce;
2711
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2787
+ rbce = ruby_curl_easy_get_handle(self);
2712
2788
 
2713
2789
  if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
2714
2790
  rbce->timeout_ms = 0;
@@ -2731,7 +2807,7 @@ static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
2731
2807
  */
2732
2808
  static VALUE ruby_curl_easy_timeout_get(VALUE self) {
2733
2809
  ruby_curl_easy *rbce;
2734
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2810
+ rbce = ruby_curl_easy_get_handle(self);
2735
2811
  return DBL2NUM(rbce->timeout_ms / 1000.0);
2736
2812
  }
2737
2813
 
@@ -2749,7 +2825,7 @@ static VALUE ruby_curl_easy_timeout_get(VALUE self) {
2749
2825
  */
2750
2826
  static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
2751
2827
  ruby_curl_easy *rbce;
2752
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2828
+ rbce = ruby_curl_easy_get_handle(self);
2753
2829
 
2754
2830
  if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
2755
2831
  rbce->timeout_ms = 0;
@@ -2769,7 +2845,7 @@ static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
2769
2845
  */
2770
2846
  static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
2771
2847
  ruby_curl_easy *rbce;
2772
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
2848
+ rbce = ruby_curl_easy_get_handle(self);
2773
2849
  return LONG2NUM(rbce->timeout_ms);
2774
2850
  }
2775
2851
 
@@ -3242,7 +3318,7 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
3242
3318
  */
3243
3319
  static VALUE ruby_curl_easy_autoreferer_set(VALUE self, VALUE autoreferer) {
3244
3320
  ruby_curl_easy *rbce;
3245
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3321
+ rbce = ruby_curl_easy_get_handle(self);
3246
3322
 
3247
3323
  if (Qtrue == autoreferer) {
3248
3324
  curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 1);
@@ -3399,7 +3475,7 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
3399
3475
  static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
3400
3476
  ruby_curl_easy *rbce;
3401
3477
  unsigned short rm;
3402
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3478
+ rbce = ruby_curl_easy_get_handle(self);
3403
3479
 
3404
3480
  rm = rbce->resolve_mode;
3405
3481
 
@@ -3431,7 +3507,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
3431
3507
  } else {
3432
3508
  ruby_curl_easy *rbce;
3433
3509
  ID resolve_mode_id;
3434
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3510
+ rbce = ruby_curl_easy_get_handle(self);
3435
3511
 
3436
3512
  resolve_mode_id = rb_to_id(resolve_mode);
3437
3513
 
@@ -3460,7 +3536,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
3460
3536
  */
3461
3537
  static VALUE ruby_curl_easy_network_policy_get(VALUE self) {
3462
3538
  ruby_curl_easy *rbce;
3463
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3539
+ rbce = ruby_curl_easy_get_handle(self);
3464
3540
 
3465
3541
  switch (rbce->network_policy) {
3466
3542
  case CURB_NETWORK_POLICY_PUBLIC:
@@ -3484,7 +3560,7 @@ static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy)
3484
3560
  ruby_curl_easy *rbce;
3485
3561
  ID network_policy_id;
3486
3562
 
3487
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3563
+ rbce = ruby_curl_easy_get_handle(self);
3488
3564
 
3489
3565
  if (NIL_P(network_policy)) {
3490
3566
  rbce->network_policy = CURB_NETWORK_POLICY_NONE;
@@ -3522,7 +3598,7 @@ static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy)
3522
3598
  */
3523
3599
  static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
3524
3600
  ruby_curl_easy *rbce;
3525
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3601
+ rbce = ruby_curl_easy_get_handle(self);
3526
3602
 
3527
3603
  if (rbce->unsafe_destination_blocked && rbce->unsafe_destination_error[0]) {
3528
3604
  return rb_str_new2(rbce->unsafe_destination_error);
@@ -3540,7 +3616,7 @@ static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
3540
3616
  */
3541
3617
  static VALUE ruby_curl_easy_unix_socket_path_get(VALUE self) {
3542
3618
  ruby_curl_easy *rbce;
3543
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3619
+ rbce = ruby_curl_easy_get_handle(self);
3544
3620
 
3545
3621
  return rb_easy_get("unix_socket_path");
3546
3622
  }
@@ -3559,7 +3635,7 @@ static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
3559
3635
  ruby_curl_easy *rbce;
3560
3636
  long http_version;
3561
3637
 
3562
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3638
+ rbce = ruby_curl_easy_get_handle(self);
3563
3639
 
3564
3640
  if (NIL_P(version)) {
3565
3641
  http_version = CURL_HTTP_VERSION_NONE;
@@ -3581,7 +3657,7 @@ static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
3581
3657
  static VALUE ruby_curl_easy_http_version_get(VALUE self) {
3582
3658
  ruby_curl_easy *rbce;
3583
3659
 
3584
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
3660
+ rbce = ruby_curl_easy_get_handle(self);
3585
3661
 
3586
3662
  return LONG2NUM(rbce->http_version);
3587
3663
  }
@@ -4364,7 +4440,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
4364
4440
  static VALUE ruby_curl_easy_setup_self(VALUE self) {
4365
4441
  ruby_curl_easy *rbce;
4366
4442
 
4367
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4443
+ rbce = ruby_curl_easy_get_handle(self);
4368
4444
  ruby_curl_easy_setup(rbce);
4369
4445
 
4370
4446
  return self;
@@ -4470,7 +4546,7 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
4470
4546
  CURL *curl;
4471
4547
  VALUE retval;
4472
4548
 
4473
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4549
+ rbce = ruby_curl_easy_get_handle(self);
4474
4550
  curl = rbce->curl;
4475
4551
 
4476
4552
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
@@ -4535,6 +4611,8 @@ struct easy_form_perform_args {
4535
4611
  struct curl_httppost *last;
4536
4612
  int clear_customrequest;
4537
4613
  int form_set_on_curl;
4614
+ ruby_curl_form_string *strings;
4615
+ ruby_curl_easy *rbce;
4538
4616
  };
4539
4617
 
4540
4618
  struct easy_join_args {
@@ -4556,15 +4634,16 @@ static VALUE join_easy_arguments(ruby_curl_easy *rbce, VALUE args_ary) {
4556
4634
 
4557
4635
  static void append_multipart_form_argument(VALUE arg,
4558
4636
  struct curl_httppost **first,
4559
- struct curl_httppost **last) {
4637
+ struct curl_httppost **last,
4638
+ ruby_curl_form_string **strings) {
4560
4639
  if (rb_obj_is_instance_of(arg, cCurlPostField)) {
4561
- append_to_form(arg, first, last);
4640
+ append_to_form(arg, first, last, strings);
4562
4641
  } else if (rb_type(arg) == T_ARRAY) {
4563
4642
  long j, argv_len = RARRAY_LEN(arg);
4564
4643
  for (j = 0; j < argv_len; ++j) {
4565
4644
  VALUE field = rb_ary_entry(arg, j);
4566
4645
  if (rb_obj_is_instance_of(field, cCurlPostField)) {
4567
- append_to_form(field, first, last);
4646
+ append_to_form(field, first, last, strings);
4568
4647
  } else {
4569
4648
  rb_raise(eCurlErrInvalidPostField,
4570
4649
  "You must use PostFields only with multipart form posts");
@@ -4579,23 +4658,35 @@ static void append_multipart_form_argument(VALUE arg,
4579
4658
  static VALUE build_and_perform_multipart_form(VALUE argp) {
4580
4659
  struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
4581
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;
4582
4667
 
4583
4668
  for (i = 0; i < args->argc; i++) {
4584
- 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);
4585
4670
  }
4586
4671
 
4587
4672
  curl_easy_setopt(args->curl, CURLOPT_POST, 0);
4588
4673
  curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, args->first);
4589
4674
  args->form_set_on_curl = 1;
4675
+ rbce->multipart_form_active = 1;
4590
4676
 
4677
+ rbce->multipart_building = 0;
4591
4678
  return call_easy_perform(args->self);
4592
4679
  }
4593
4680
 
4594
4681
  static VALUE ensure_free_form_post(VALUE argp) {
4595
4682
  struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
4683
+ if (args->rbce) args->rbce->multipart_building = 0;
4596
4684
  if (args->curl) {
4597
4685
  if (args->form_set_on_curl) {
4686
+ ruby_curl_easy *rbce;
4687
+ rbce = ruby_curl_easy_get_handle(args->self);
4598
4688
  curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, NULL);
4689
+ rbce->multipart_form_active = 0;
4599
4690
  }
4600
4691
  if (args->clear_customrequest) {
4601
4692
  curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
@@ -4606,6 +4697,9 @@ static VALUE ensure_free_form_post(VALUE argp) {
4606
4697
  args->first = NULL;
4607
4698
  }
4608
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);
4609
4703
  return Qnil;
4610
4704
  }
4611
4705
 
@@ -4640,7 +4734,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
4640
4734
 
4641
4735
  rb_scan_args(argc, argv, "*", &args_ary);
4642
4736
 
4643
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4737
+ rbce = ruby_curl_easy_get_handle(self);
4644
4738
  curl = rbce->curl;
4645
4739
 
4646
4740
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
@@ -4649,7 +4743,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
4649
4743
 
4650
4744
  if (rbce->multipart_form_post) {
4651
4745
  VALUE ret;
4652
- 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 };
4653
4747
  ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
4654
4748
 
4655
4749
  return ret;
@@ -4699,7 +4793,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
4699
4793
  VALUE args_ary;
4700
4794
 
4701
4795
  rb_scan_args(argc, argv, "*", &args_ary);
4702
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4796
+ rbce = ruby_curl_easy_get_handle(self);
4703
4797
  curl = rbce->curl;
4704
4798
 
4705
4799
  /* Clear the error buffer */
@@ -4710,7 +4804,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
4710
4804
 
4711
4805
  if (rbce->multipart_form_post) {
4712
4806
  VALUE ret;
4713
- 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 };
4714
4808
  ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
4715
4809
  return ret;
4716
4810
  } else {
@@ -4748,7 +4842,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
4748
4842
  VALUE args_ary;
4749
4843
 
4750
4844
  rb_scan_args(argc, argv, "*", &args_ary);
4751
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4845
+ rbce = ruby_curl_easy_get_handle(self);
4752
4846
  curl = rbce->curl;
4753
4847
 
4754
4848
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
@@ -4768,7 +4862,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
4768
4862
  /* Otherwise, if multipart_form_post is true, use multipart logic */
4769
4863
  else if (rbce->multipart_form_post) {
4770
4864
  VALUE ret;
4771
- 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 };
4772
4866
  ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
4773
4867
  return ret;
4774
4868
  }
@@ -4815,7 +4909,7 @@ static VALUE ruby_curl_easy_max_body_bytes_set(VALUE self, VALUE val) {
4815
4909
  ruby_curl_easy *rbce;
4816
4910
  long long limit;
4817
4911
 
4818
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4912
+ rbce = ruby_curl_easy_get_handle(self);
4819
4913
 
4820
4914
  if (NIL_P(val)) {
4821
4915
  rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
@@ -4870,10 +4964,10 @@ static VALUE ruby_curl_easy_header_str_get(VALUE self) {
4870
4964
  */
4871
4965
  static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
4872
4966
  ruby_curl_easy *rbce;
4873
- char* url;
4967
+ char* url = NULL;
4874
4968
 
4875
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4876
- 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);
4877
4971
 
4878
4972
  if (url && url[0]) { // curl returns empty string if none
4879
4973
  return rb_str_new2(url);
@@ -4893,14 +4987,14 @@ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
4893
4987
  */
4894
4988
  static VALUE ruby_curl_easy_response_code_get(VALUE self) {
4895
4989
  ruby_curl_easy *rbce;
4896
- long code;
4990
+ long code = 0;
4897
4991
 
4898
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4992
+ rbce = ruby_curl_easy_get_handle(self);
4899
4993
  #ifdef HAVE_CURLINFO_RESPONSE_CODE
4900
- curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
4994
+ CURB_GETINFO(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
4901
4995
  #else
4902
4996
  // old libcurl
4903
- curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CODE, &code);
4997
+ CURB_GETINFO(rbce->curl, CURLINFO_HTTP_CODE, &code);
4904
4998
  #endif
4905
4999
 
4906
5000
  return LONG2NUM(code);
@@ -4917,10 +5011,10 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
4917
5011
  */
4918
5012
  static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
4919
5013
  ruby_curl_easy *rbce;
4920
- char* ip;
5014
+ char* ip = NULL;
4921
5015
 
4922
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4923
- 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);
4924
5018
 
4925
5019
  if (ip && ip[0]) { // curl returns empty string if none
4926
5020
  return rb_str_new2(ip);
@@ -4938,10 +5032,10 @@ static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
4938
5032
  */
4939
5033
  static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
4940
5034
  ruby_curl_easy *rbce;
4941
- long code;
5035
+ long code = 0;
4942
5036
 
4943
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4944
- 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);
4945
5039
 
4946
5040
  return LONG2NUM(code);
4947
5041
  }
@@ -4966,10 +5060,10 @@ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
4966
5060
  static VALUE ruby_curl_easy_file_time_get(VALUE self) {
4967
5061
  #ifdef HAVE_CURLINFO_FILETIME
4968
5062
  ruby_curl_easy *rbce;
4969
- long time;
5063
+ long time = 0;
4970
5064
 
4971
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4972
- curl_easy_getinfo(rbce->curl, CURLINFO_FILETIME, &time);
5065
+ rbce = ruby_curl_easy_get_handle(self);
5066
+ CURB_GETINFO(rbce->curl, CURLINFO_FILETIME, &time);
4973
5067
 
4974
5068
  return LONG2NUM(time);
4975
5069
  #else
@@ -4987,10 +5081,10 @@ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
4987
5081
  */
4988
5082
  static VALUE ruby_curl_easy_total_time_get(VALUE self) {
4989
5083
  ruby_curl_easy *rbce;
4990
- double time;
5084
+ double time = 0;
4991
5085
 
4992
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
4993
- 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);
4994
5088
 
4995
5089
  return rb_float_new(time);
4996
5090
  }
@@ -5004,10 +5098,10 @@ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
5004
5098
  */
5005
5099
  static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
5006
5100
  ruby_curl_easy *rbce;
5007
- double time;
5101
+ double time = 0;
5008
5102
 
5009
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5010
- 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);
5011
5105
 
5012
5106
  return rb_float_new(time);
5013
5107
  }
@@ -5021,10 +5115,10 @@ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
5021
5115
  */
5022
5116
  static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
5023
5117
  ruby_curl_easy *rbce;
5024
- double time;
5118
+ double time = 0;
5025
5119
 
5026
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5027
- 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);
5028
5122
 
5029
5123
  return rb_float_new(time);
5030
5124
  }
@@ -5042,10 +5136,10 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
5042
5136
  #if defined(HAVE_CURLINFO_APPCONNECT_TIME)
5043
5137
  static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
5044
5138
  ruby_curl_easy *rbce;
5045
- double time;
5139
+ double time = 0;
5046
5140
 
5047
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5048
- 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);
5049
5143
 
5050
5144
  return rb_float_new(time);
5051
5145
  }
@@ -5063,10 +5157,10 @@ static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
5063
5157
  */
5064
5158
  static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
5065
5159
  ruby_curl_easy *rbce;
5066
- double time;
5160
+ double time = 0;
5067
5161
 
5068
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5069
- 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);
5070
5164
 
5071
5165
  return rb_float_new(time);
5072
5166
  }
@@ -5081,10 +5175,10 @@ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
5081
5175
  */
5082
5176
  static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
5083
5177
  ruby_curl_easy *rbce;
5084
- double time;
5178
+ double time = 0;
5085
5179
 
5086
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5087
- 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);
5088
5182
 
5089
5183
  return rb_float_new(time);
5090
5184
  }
@@ -5103,10 +5197,10 @@ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
5103
5197
  static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
5104
5198
  #ifdef HAVE_CURLINFO_REDIRECT_TIME
5105
5199
  ruby_curl_easy *rbce;
5106
- double time;
5200
+ double time = 0;
5107
5201
 
5108
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5109
- 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);
5110
5204
 
5111
5205
  return rb_float_new(time);
5112
5206
  #else
@@ -5126,10 +5220,10 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
5126
5220
  static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
5127
5221
  #ifdef HAVE_CURLINFO_REDIRECT_COUNT
5128
5222
  ruby_curl_easy *rbce;
5129
- long count;
5223
+ long count = 0;
5130
5224
 
5131
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5132
- 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);
5133
5227
 
5134
5228
  return LONG2NUM(count);
5135
5229
  #else
@@ -5151,10 +5245,10 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
5151
5245
  static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
5152
5246
  #ifdef HAVE_CURLINFO_REDIRECT_URL
5153
5247
  ruby_curl_easy *rbce;
5154
- char* url;
5248
+ char* url = NULL;
5155
5249
 
5156
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5157
- 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);
5158
5252
 
5159
5253
  if (url && url[0]) { // curl returns empty string if none
5160
5254
  return rb_str_new2(url);
@@ -5178,15 +5272,15 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
5178
5272
  */
5179
5273
  static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
5180
5274
  ruby_curl_easy *rbce;
5181
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5275
+ rbce = ruby_curl_easy_get_handle(self);
5182
5276
 
5183
5277
  #ifdef HAVE_CURLINFO_SIZE_UPLOAD_T
5184
- curl_off_t bytes;
5185
- 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);
5186
5280
  return LL2NUM(bytes);
5187
5281
  #else
5188
- double bytes;
5189
- curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
5282
+ double bytes = 0;
5283
+ CURB_GETINFO(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
5190
5284
  return rb_float_new(bytes);
5191
5285
  #endif
5192
5286
  }
@@ -5200,15 +5294,15 @@ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
5200
5294
  */
5201
5295
  static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
5202
5296
  ruby_curl_easy *rbce;
5203
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5297
+ rbce = ruby_curl_easy_get_handle(self);
5204
5298
 
5205
5299
  #ifdef HAVE_CURLINFO_SIZE_DOWNLOAD_T
5206
- curl_off_t bytes;
5207
- 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);
5208
5302
  return LL2NUM(bytes);
5209
5303
  #else
5210
- double bytes;
5211
- curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
5304
+ double bytes = 0;
5305
+ CURB_GETINFO(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
5212
5306
  return rb_float_new(bytes);
5213
5307
  #endif
5214
5308
  }
@@ -5222,15 +5316,15 @@ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
5222
5316
  */
5223
5317
  static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
5224
5318
  ruby_curl_easy *rbce;
5225
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5319
+ rbce = ruby_curl_easy_get_handle(self);
5226
5320
 
5227
5321
  #ifdef HAVE_CURLINFO_SPEED_UPLOAD_T
5228
- curl_off_t bytes;
5229
- 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);
5230
5324
  return LL2NUM(bytes);
5231
5325
  #else
5232
- double bytes;
5233
- curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
5326
+ double bytes = 0;
5327
+ CURB_GETINFO(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
5234
5328
  return rb_float_new(bytes);
5235
5329
  #endif
5236
5330
  }
@@ -5244,15 +5338,15 @@ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
5244
5338
  */
5245
5339
  static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
5246
5340
  ruby_curl_easy *rbce;
5247
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5341
+ rbce = ruby_curl_easy_get_handle(self);
5248
5342
 
5249
5343
  #ifdef HAVE_CURLINFO_SPEED_DOWNLOAD_T
5250
- curl_off_t bytes;
5251
- 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);
5252
5346
  return LL2NUM(bytes);
5253
5347
  #else
5254
- double bytes;
5255
- curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
5348
+ double bytes = 0;
5349
+ CURB_GETINFO(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
5256
5350
  return rb_float_new(bytes);
5257
5351
  #endif
5258
5352
  }
@@ -5266,10 +5360,10 @@ static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
5266
5360
  */
5267
5361
  static VALUE ruby_curl_easy_header_size_get(VALUE self) {
5268
5362
  ruby_curl_easy *rbce;
5269
- long size;
5363
+ long size = 0;
5270
5364
 
5271
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5272
- 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);
5273
5367
 
5274
5368
  return LONG2NUM(size);
5275
5369
  }
@@ -5284,10 +5378,10 @@ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
5284
5378
  */
5285
5379
  static VALUE ruby_curl_easy_request_size_get(VALUE self) {
5286
5380
  ruby_curl_easy *rbce;
5287
- long size;
5381
+ long size = 0;
5288
5382
 
5289
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5290
- 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);
5291
5385
 
5292
5386
  return LONG2NUM(size);
5293
5387
  }
@@ -5301,10 +5395,10 @@ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
5301
5395
  */
5302
5396
  static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
5303
5397
  ruby_curl_easy *rbce;
5304
- long result;
5398
+ long result = 0;
5305
5399
 
5306
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5307
- 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);
5308
5402
 
5309
5403
  return LONG2NUM(result);
5310
5404
  }
@@ -5326,15 +5420,15 @@ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done
5326
5420
  */
5327
5421
  static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
5328
5422
  ruby_curl_easy *rbce;
5329
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5423
+ rbce = ruby_curl_easy_get_handle(self);
5330
5424
 
5331
5425
  #ifdef HAVE_CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
5332
- curl_off_t bytes;
5333
- 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);
5334
5428
  return LL2NUM(bytes);
5335
5429
  #else
5336
- double bytes;
5337
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
5430
+ double bytes = 0;
5431
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
5338
5432
  return rb_float_new(bytes);
5339
5433
  #endif
5340
5434
  }
@@ -5347,15 +5441,15 @@ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
5347
5441
  */
5348
5442
  static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
5349
5443
  ruby_curl_easy *rbce;
5350
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5444
+ rbce = ruby_curl_easy_get_handle(self);
5351
5445
 
5352
5446
  #ifdef HAVE_CURLINFO_CONTENT_LENGTH_UPLOAD_T
5353
- curl_off_t bytes;
5354
- 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);
5355
5449
  return LL2NUM(bytes);
5356
5450
  #else
5357
- double bytes;
5358
- curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
5451
+ double bytes = 0;
5452
+ CURB_GETINFO(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
5359
5453
  return rb_float_new(bytes);
5360
5454
  #endif
5361
5455
  }
@@ -5371,10 +5465,10 @@ static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
5371
5465
  */
5372
5466
  static VALUE ruby_curl_easy_content_type_get(VALUE self) {
5373
5467
  ruby_curl_easy *rbce;
5374
- char* type;
5468
+ char* type = NULL;
5375
5469
 
5376
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5377
- 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);
5378
5472
 
5379
5473
  if (type && type[0]) { // curl returns empty string if none
5380
5474
  return rb_str_new2(type);
@@ -5414,10 +5508,10 @@ Pass a pointer to a long to receive a bitmask indicating the authentication meth
5414
5508
  static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
5415
5509
  #ifdef HAVE_CURLINFO_OS_ERRNO
5416
5510
  ruby_curl_easy *rbce;
5417
- long result;
5511
+ long result = 0;
5418
5512
 
5419
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5420
- 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);
5421
5515
 
5422
5516
  return LONG2NUM(result);
5423
5517
  #else
@@ -5443,10 +5537,10 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
5443
5537
  static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
5444
5538
  #ifdef HAVE_CURLINFO_NUM_CONNECTS
5445
5539
  ruby_curl_easy *rbce;
5446
- long result;
5540
+ long result = 0;
5447
5541
 
5448
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5449
- 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);
5450
5544
 
5451
5545
  return LONG2NUM(result);
5452
5546
  #else
@@ -5478,12 +5572,12 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
5478
5572
  static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
5479
5573
  #ifdef HAVE_CURLINFO_COOKIELIST
5480
5574
  ruby_curl_easy *rbce;
5481
- struct curl_slist *cookies;
5575
+ struct curl_slist *cookies = NULL;
5482
5576
  struct curl_slist *cookie;
5483
5577
  VALUE rb_cookies;
5484
5578
 
5485
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5486
- curl_easy_getinfo(rbce->curl, CURLINFO_COOKIELIST, &cookies);
5579
+ rbce = ruby_curl_easy_get_handle(self);
5580
+ CURB_GETINFO(rbce->curl, CURLINFO_COOKIELIST, &cookies);
5487
5581
  if (!cookies)
5488
5582
  return Qnil;
5489
5583
  rb_cookies = rb_ary_new();
@@ -5522,8 +5616,8 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
5522
5616
  ruby_curl_easy *rbce;
5523
5617
  char* path = NULL;
5524
5618
 
5525
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5526
- 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);
5527
5621
 
5528
5622
  if (path && path[0]) { // curl returns NULL or empty string if none
5529
5623
  return rb_str_new2(path);
@@ -5542,7 +5636,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
5542
5636
  */
5543
5637
  static VALUE ruby_curl_easy_multi_get(VALUE self) {
5544
5638
  ruby_curl_easy *rbce;
5545
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5639
+ rbce = ruby_curl_easy_get_handle(self);
5546
5640
  return rbce->multi;
5547
5641
  }
5548
5642
 
@@ -5555,7 +5649,7 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
5555
5649
  VALUE old_multi;
5556
5650
  ruby_curl_multi *old_rbcm;
5557
5651
  CURLMcode result;
5558
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5652
+ rbce = ruby_curl_easy_get_handle(self);
5559
5653
 
5560
5654
  if (!NIL_P(multi) && rb_obj_is_kind_of(multi, cCurlMulti) != Qtrue) {
5561
5655
  rb_raise(rb_eTypeError, "expected Curl::Multi or nil");
@@ -5584,7 +5678,7 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
5584
5678
  */
5585
5679
  static VALUE ruby_curl_easy_last_result(VALUE self) {
5586
5680
  ruby_curl_easy *rbce;
5587
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5681
+ rbce = ruby_curl_easy_get_handle(self);
5588
5682
  return LONG2NUM(rbce->last_result);
5589
5683
  }
5590
5684
 
@@ -5594,7 +5688,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
5594
5688
  */
5595
5689
  static VALUE ruby_curl_easy_last_error(VALUE self) {
5596
5690
  ruby_curl_easy *rbce;
5597
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
5691
+ rbce = ruby_curl_easy_get_handle(self);
5598
5692
 
5599
5693
  if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
5600
5694
  return rb_str_new2(rbce->err_buf);
@@ -5632,7 +5726,8 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
5632
5726
  long option = NUM2LONG(opt);
5633
5727
  rb_io_t *open_f_ptr;
5634
5728
 
5635
- 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);
5636
5731
 
5637
5732
  switch (option) {
5638
5733
  /* BEHAVIOR OPTIONS */
@@ -6084,6 +6179,28 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
6084
6179
 
6085
6180
  /* ================== ESCAPING FUNCS ==============*/
6086
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
+
6087
6204
  /*
6088
6205
  * call-seq:
6089
6206
  * easy.escape("some text") => "some%20text"
@@ -6096,10 +6213,9 @@ static VALUE ruby_curl_easy_inspect(VALUE self) {
6096
6213
  static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
6097
6214
  ruby_curl_easy *rbce;
6098
6215
  char *result;
6099
- VALUE rresult;
6100
6216
  VALUE str = svalue;
6101
6217
 
6102
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
6218
+ rbce = ruby_curl_easy_get_handle(self);
6103
6219
 
6104
6220
  /* NOTE: make sure the value is a string; rb_obj_as_string always yields a
6105
6221
  * String, even if the object's to_s misbehaves and returns a non-String. */
@@ -6111,10 +6227,8 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
6111
6227
  result = (char*)curl_escape(StringValuePtr(str), (int)RSTRING_LEN(str));
6112
6228
  #endif
6113
6229
 
6114
- rresult = rb_str_new2(result);
6115
- curl_free(result);
6116
-
6117
- return rresult;
6230
+ if (!result) rb_raise(eCurlErrError, "Failed to URL-encode string");
6231
+ return curl_string_result_to_ruby(result, (long)strlen(result));
6118
6232
  }
6119
6233
 
6120
6234
  /*
@@ -6129,9 +6243,8 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
6129
6243
  ruby_curl_easy *rbce;
6130
6244
  int rlen;
6131
6245
  char *result;
6132
- VALUE rresult;
6133
6246
 
6134
- TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
6247
+ rbce = ruby_curl_easy_get_handle(self);
6135
6248
 
6136
6249
  /* Coerce as its own statement before use below - StringValuePtr and
6137
6250
  * RSTRING_LEN are sibling args to the same call and C does not guarantee
@@ -6142,13 +6255,13 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
6142
6255
  result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
6143
6256
  #else
6144
6257
  result = (char*)curl_unescape(StringValuePtr(str), (int)RSTRING_LEN(str));
6145
- rlen = strlen(result);
6146
6258
  #endif
6147
6259
 
6148
- rresult = rb_str_new(result, rlen);
6149
- curl_free(result);
6150
-
6151
- 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);
6152
6265
  }
6153
6266
 
6154
6267