curb 0.9.11 → 1.0.5
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.
- checksums.yaml +4 -4
- data/README.markdown +48 -6
- data/Rakefile +17 -18
- data/ext/curb.c +154 -8
- data/ext/curb.h +10 -5
- data/ext/curb_easy.c +100 -44
- data/ext/curb_easy.h +3 -0
- data/ext/curb_macros.h +12 -0
- data/ext/curb_multi.c +50 -24
- data/ext/curb_postfield.c +9 -7
- data/ext/curb_upload.c +1 -0
- data/ext/extconf.rb +38 -0
- data/lib/curl/easy.rb +8 -7
- data/lib/curl/multi.rb +8 -1
- data/lib/curl.rb +11 -3
- data/tests/bug_crash_on_debug.rb +14 -28
- data/tests/bug_crash_on_progress.rb +7 -31
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +8 -13
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
- data/tests/bug_follow_redirect_288.rb +83 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_raise_on_callback.rb +29 -0
- data/tests/helper.rb +26 -1
- data/tests/tc_curl_easy.rb +13 -5
- data/tests/tc_curl_multi.rb +98 -17
- data/tests/tc_curl_protocols.rb +37 -0
- data/tests/timeout.rb +21 -5
- metadata +28 -22
data/ext/curb_easy.c
CHANGED
@@ -34,7 +34,7 @@ static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
|
34
34
|
|
35
35
|
/* ================== CURL HANDLER FUNCS ==============*/
|
36
36
|
|
37
|
-
static VALUE callback_exception(VALUE unused) {
|
37
|
+
static VALUE callback_exception(VALUE unused, VALUE exception) {
|
38
38
|
return Qfalse;
|
39
39
|
}
|
40
40
|
|
@@ -268,6 +268,8 @@ void curl_easy_free(ruby_curl_easy *rbce) {
|
|
268
268
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
269
269
|
rbce->opts = rb_hash_new();
|
270
270
|
|
271
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
272
|
+
|
271
273
|
rbce->curl_headers = NULL;
|
272
274
|
rbce->curl_proxy_headers = NULL;
|
273
275
|
rbce->curl_ftp_commands = NULL;
|
@@ -327,9 +329,9 @@ static VALUE ruby_curl_easy_allocate(VALUE klass) {
|
|
327
329
|
|
328
330
|
/*
|
329
331
|
* call-seq:
|
330
|
-
* Curl::Easy.new =>
|
331
|
-
* Curl::Easy.new(url = nil) =>
|
332
|
-
* Curl::Easy.new(url = nil) { |self| ... } =>
|
332
|
+
* Curl::Easy.new => #<Curl::Easy...>
|
333
|
+
* Curl::Easy.new(url = nil) => #<Curl::Easy...>
|
334
|
+
* Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
|
333
335
|
*
|
334
336
|
* Initialize a new Curl::Easy instance, optionally supplying the URL.
|
335
337
|
* The block form allows further configuration to be supplied before
|
@@ -355,8 +357,9 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
355
357
|
|
356
358
|
ruby_curl_easy_zero(rbce);
|
357
359
|
|
358
|
-
|
360
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
359
361
|
|
362
|
+
rb_easy_set("url", url);
|
360
363
|
|
361
364
|
/* set the pointer to the curl handle */
|
362
365
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
|
@@ -373,8 +376,8 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
373
376
|
|
374
377
|
/*
|
375
378
|
* call-seq:
|
376
|
-
* easy.clone =>
|
377
|
-
* easy.dup =>
|
379
|
+
* easy.clone => <easy clone>
|
380
|
+
* easy.dup => <easy clone>
|
378
381
|
*
|
379
382
|
* Clone this Curl::Easy instance, creating a new instance.
|
380
383
|
* This method duplicates the underlying CURL* handle.
|
@@ -392,6 +395,8 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
392
395
|
newrbce->curl_ftp_commands = NULL;
|
393
396
|
newrbce->curl_resolve = NULL;
|
394
397
|
|
398
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
399
|
+
|
395
400
|
return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
|
396
401
|
}
|
397
402
|
|
@@ -461,7 +466,9 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
461
466
|
curl_easy_reset(rbce->curl);
|
462
467
|
ruby_curl_easy_zero(rbce);
|
463
468
|
|
464
|
-
|
469
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
470
|
+
|
471
|
+
/* reset clobbers the private setting, so reset it to self */
|
465
472
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
|
466
473
|
if (ecode != CURLE_OK) {
|
467
474
|
raise_curl_easy_error_exception(ecode);
|
@@ -950,7 +957,7 @@ static VALUE ruby_curl_easy_ftp_commands_set(VALUE self, VALUE ftp_commands) {
|
|
950
957
|
}
|
951
958
|
|
952
959
|
/*
|
953
|
-
* call-seq
|
960
|
+
* call-seq:
|
954
961
|
* easy.ftp_commands => array or nil
|
955
962
|
*/
|
956
963
|
static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
|
@@ -969,7 +976,7 @@ static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
|
|
969
976
|
}
|
970
977
|
|
971
978
|
/*
|
972
|
-
* call-seq
|
979
|
+
* call-seq:
|
973
980
|
* easy.resolve => array or nil
|
974
981
|
*/
|
975
982
|
static VALUE ruby_curl_easy_resolve_get(VALUE self) {
|
@@ -1304,7 +1311,7 @@ static VALUE ruby_curl_easy_connect_timeout_set(VALUE self, VALUE connect_timeou
|
|
1304
1311
|
* Obtain the maximum time in seconds that you allow the connection to the
|
1305
1312
|
* server to take.
|
1306
1313
|
*/
|
1307
|
-
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self
|
1314
|
+
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self) {
|
1308
1315
|
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
|
1309
1316
|
}
|
1310
1317
|
|
@@ -1330,7 +1337,7 @@ static VALUE ruby_curl_easy_connect_timeout_ms_set(VALUE self, VALUE connect_tim
|
|
1330
1337
|
* Obtain the maximum time in milliseconds that you allow the connection to the
|
1331
1338
|
* server to take.
|
1332
1339
|
*/
|
1333
|
-
static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self
|
1340
|
+
static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self) {
|
1334
1341
|
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout_ms, 0);
|
1335
1342
|
}
|
1336
1343
|
|
@@ -1353,7 +1360,7 @@ static VALUE ruby_curl_easy_dns_cache_timeout_set(VALUE self, VALUE dns_cache_ti
|
|
1353
1360
|
*
|
1354
1361
|
* Obtain the dns cache timeout in seconds.
|
1355
1362
|
*/
|
1356
|
-
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self
|
1363
|
+
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self) {
|
1357
1364
|
CURB_IMMED_GETTER(ruby_curl_easy, dns_cache_timeout, -1);
|
1358
1365
|
}
|
1359
1366
|
|
@@ -1380,7 +1387,7 @@ static VALUE ruby_curl_easy_ftp_response_timeout_set(VALUE self, VALUE ftp_respo
|
|
1380
1387
|
*
|
1381
1388
|
* Obtain the maximum time that libcurl will wait for FTP command responses.
|
1382
1389
|
*/
|
1383
|
-
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self
|
1390
|
+
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self) {
|
1384
1391
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
|
1385
1392
|
}
|
1386
1393
|
|
@@ -1403,7 +1410,7 @@ static VALUE ruby_curl_easy_low_speed_limit_set(VALUE self, VALUE low_speed_limi
|
|
1403
1410
|
* Obtain the minimum transfer speed over +low_speed+time+ below which the
|
1404
1411
|
* transfer will be aborted.
|
1405
1412
|
*/
|
1406
|
-
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self
|
1413
|
+
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self) {
|
1407
1414
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_limit, 0);
|
1408
1415
|
}
|
1409
1416
|
|
@@ -1425,7 +1432,7 @@ static VALUE ruby_curl_easy_low_speed_time_set(VALUE self, VALUE low_speed_time)
|
|
1425
1432
|
* Obtain the time that the transfer should be below +low_speed_limit+ for
|
1426
1433
|
* the library to abort it.
|
1427
1434
|
*/
|
1428
|
-
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self
|
1435
|
+
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self) {
|
1429
1436
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
|
1430
1437
|
}
|
1431
1438
|
|
@@ -1445,7 +1452,7 @@ static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_
|
|
1445
1452
|
*
|
1446
1453
|
* Get the maximal sending transfer speed (in bytes per second)
|
1447
1454
|
*/
|
1448
|
-
static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self
|
1455
|
+
static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self) {
|
1449
1456
|
CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
|
1450
1457
|
}
|
1451
1458
|
|
@@ -1465,7 +1472,7 @@ static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_
|
|
1465
1472
|
*
|
1466
1473
|
* Get the maximal receiving transfer speed (in bytes per second)
|
1467
1474
|
*/
|
1468
|
-
static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self
|
1475
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self) {
|
1469
1476
|
CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
1470
1477
|
}
|
1471
1478
|
|
@@ -1489,7 +1496,7 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
|
|
1489
1496
|
*
|
1490
1497
|
* Get the current username
|
1491
1498
|
*/
|
1492
|
-
static VALUE ruby_curl_easy_username_get(VALUE self
|
1499
|
+
static VALUE ruby_curl_easy_username_get(VALUE self) {
|
1493
1500
|
#if HAVE_CURLOPT_USERNAME
|
1494
1501
|
CURB_OBJECT_HGETTER(ruby_curl_easy, username);
|
1495
1502
|
#else
|
@@ -1517,7 +1524,7 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
|
|
1517
1524
|
*
|
1518
1525
|
* Get the current password
|
1519
1526
|
*/
|
1520
|
-
static VALUE ruby_curl_easy_password_get(VALUE self
|
1527
|
+
static VALUE ruby_curl_easy_password_get(VALUE self) {
|
1521
1528
|
#if HAVE_CURLOPT_PASSWORD
|
1522
1529
|
CURB_OBJECT_HGETTER(ruby_curl_easy, password);
|
1523
1530
|
#else
|
@@ -1539,6 +1546,7 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
|
|
1539
1546
|
* Curl::CURL_SSLVERSION_TLSv1_0
|
1540
1547
|
* Curl::CURL_SSLVERSION_TLSv1_1
|
1541
1548
|
* Curl::CURL_SSLVERSION_TLSv1_2
|
1549
|
+
* Curl::CURL_SSLVERSION_TLSv1_3
|
1542
1550
|
*/
|
1543
1551
|
static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
1544
1552
|
CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
|
@@ -1550,7 +1558,7 @@ static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
|
1550
1558
|
*
|
1551
1559
|
* Get the version of SSL/TLS that libcurl will attempt to use.
|
1552
1560
|
*/
|
1553
|
-
static VALUE ruby_curl_easy_ssl_version_get(VALUE self
|
1561
|
+
static VALUE ruby_curl_easy_ssl_version_get(VALUE self) {
|
1554
1562
|
CURB_IMMED_GETTER(ruby_curl_easy, ssl_version, -1);
|
1555
1563
|
}
|
1556
1564
|
|
@@ -1571,7 +1579,7 @@ static VALUE ruby_curl_easy_use_ssl_set(VALUE self, VALUE use_ssl) {
|
|
1571
1579
|
*
|
1572
1580
|
* Get the desired level for using SSL on FTP connections.
|
1573
1581
|
*/
|
1574
|
-
static VALUE ruby_curl_easy_use_ssl_get(VALUE self
|
1582
|
+
static VALUE ruby_curl_easy_use_ssl_get(VALUE self) {
|
1575
1583
|
CURB_IMMED_GETTER(ruby_curl_easy, use_ssl, -1);
|
1576
1584
|
}
|
1577
1585
|
|
@@ -1587,12 +1595,12 @@ static VALUE ruby_curl_easy_ftp_filemethod_set(VALUE self, VALUE ftp_filemethod)
|
|
1587
1595
|
}
|
1588
1596
|
|
1589
1597
|
/*
|
1590
|
-
* call-seq
|
1598
|
+
* call-seq:
|
1591
1599
|
* easy.ftp_filemethod => fixnum
|
1592
1600
|
*
|
1593
1601
|
* Get the configuration for how libcurl will reach files on the server.
|
1594
1602
|
*/
|
1595
|
-
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self
|
1603
|
+
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self) {
|
1596
1604
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_filemethod, -1);
|
1597
1605
|
}
|
1598
1606
|
|
@@ -1959,7 +1967,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
1959
1967
|
|
1960
1968
|
/*
|
1961
1969
|
* call-seq:
|
1962
|
-
* easy.on_body { |body_data| ... } =>
|
1970
|
+
* easy.on_body { |body_data| ... } => <old handler>
|
1963
1971
|
*
|
1964
1972
|
* Assign or remove the +on_body+ handler for this Curl::Easy instance.
|
1965
1973
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1978,7 +1986,7 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
|
|
1978
1986
|
|
1979
1987
|
/*
|
1980
1988
|
* call-seq:
|
1981
|
-
* easy.on_success { |easy| ... } =>
|
1989
|
+
* easy.on_success { |easy| ... } => <old handler>
|
1982
1990
|
*
|
1983
1991
|
* Assign or remove the +on_success+ handler for this Curl::Easy instance.
|
1984
1992
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1993,7 +2001,7 @@ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
|
|
1993
2001
|
|
1994
2002
|
/*
|
1995
2003
|
* call-seq:
|
1996
|
-
* easy.on_failure {|easy,code| ... } =>
|
2004
|
+
* easy.on_failure {|easy,code| ... } => <old handler>
|
1997
2005
|
*
|
1998
2006
|
* Assign or remove the +on_failure+ handler for this Curl::Easy instance.
|
1999
2007
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2008,7 +2016,7 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
|
|
2008
2016
|
|
2009
2017
|
/*
|
2010
2018
|
* call-seq:
|
2011
|
-
* easy.on_missing {|easy,code| ... } =>
|
2019
|
+
* easy.on_missing {|easy,code| ... } => <old handler;>
|
2012
2020
|
*
|
2013
2021
|
* Assign or remove the on_missing handler for this Curl::Easy instance.
|
2014
2022
|
* To remove a previously-supplied handler, call this method with no attached
|
@@ -2023,7 +2031,7 @@ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
2023
2031
|
|
2024
2032
|
/*
|
2025
2033
|
* call-seq:
|
2026
|
-
* easy.on_redirect {|easy,code| ... } =>
|
2034
|
+
* easy.on_redirect {|easy,code| ... } => <old handler;>
|
2027
2035
|
*
|
2028
2036
|
* Assign or remove the on_redirect handler for this Curl::Easy instance.
|
2029
2037
|
* To remove a previously-supplied handler, call this method with no attached
|
@@ -2038,7 +2046,7 @@ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
2038
2046
|
|
2039
2047
|
/*
|
2040
2048
|
* call-seq:
|
2041
|
-
* easy.on_complete {|easy| ... } =>
|
2049
|
+
* easy.on_complete {|easy| ... } => <old handler>
|
2042
2050
|
*
|
2043
2051
|
* Assign or remove the +on_complete+ handler for this Curl::Easy instance.
|
2044
2052
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2052,7 +2060,7 @@ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
|
|
2052
2060
|
|
2053
2061
|
/*
|
2054
2062
|
* call-seq:
|
2055
|
-
* easy.on_header { |header_data| ... } =>
|
2063
|
+
* easy.on_header { |header_data| ... } => <old handler>
|
2056
2064
|
*
|
2057
2065
|
* Assign or remove the +on_header+ handler for this Curl::Easy instance.
|
2058
2066
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2068,7 +2076,7 @@ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
|
|
2068
2076
|
|
2069
2077
|
/*
|
2070
2078
|
* call-seq:
|
2071
|
-
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } =>
|
2079
|
+
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } => <old handler>
|
2072
2080
|
*
|
2073
2081
|
* Assign or remove the +on_progress+ handler for this Curl::Easy instance.
|
2074
2082
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2089,7 +2097,7 @@ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
|
|
2089
2097
|
|
2090
2098
|
/*
|
2091
2099
|
* call-seq:
|
2092
|
-
* easy.on_debug { |type, data| ... } =>
|
2100
|
+
* easy.on_debug { |type, data| ... } => <old handler>
|
2093
2101
|
*
|
2094
2102
|
* Assign or remove the +on_debug+ handler for this Curl::Easy instance.
|
2095
2103
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2114,7 +2122,7 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
|
|
2114
2122
|
/***********************************************
|
2115
2123
|
* This is an rb_iterate callback used to set up http headers.
|
2116
2124
|
*/
|
2117
|
-
static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
2125
|
+
static VALUE cb_each_http_header(VALUE header, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
2118
2126
|
struct curl_slist **list;
|
2119
2127
|
VALUE header_str = Qnil;
|
2120
2128
|
|
@@ -2128,11 +2136,14 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
2128
2136
|
|
2129
2137
|
name = rb_obj_as_string(rb_ary_entry(header, 0));
|
2130
2138
|
value = rb_obj_as_string(rb_ary_entry(header, 1));
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2139
|
+
if (rb_str_strlen(value) == 0) { // removing the header e.g. Accept: with nothing trailing should remove it see: https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html
|
2140
|
+
header_str = rb_str_plus(name, rb_str_new2(":"));
|
2141
|
+
} else {
|
2142
|
+
// This is a bit inefficient, but we don't want to be modifying
|
2143
|
+
// the actual values in the original hash.
|
2144
|
+
header_str = rb_str_plus(name, rb_str_new2(": "));
|
2145
|
+
header_str = rb_str_plus(header_str, value);
|
2146
|
+
}
|
2136
2147
|
} else {
|
2137
2148
|
header_str = rb_obj_as_string(header);
|
2138
2149
|
}
|
@@ -2146,7 +2157,7 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
2146
2157
|
/***********************************************
|
2147
2158
|
* This is an rb_iterate callback used to set up http proxy headers.
|
2148
2159
|
*/
|
2149
|
-
static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap) {
|
2160
|
+
static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
2150
2161
|
struct curl_slist **list;
|
2151
2162
|
VALUE proxy_header_str = Qnil;
|
2152
2163
|
|
@@ -2178,7 +2189,7 @@ static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap) {
|
|
2178
2189
|
/***********************************************
|
2179
2190
|
* This is an rb_iterate callback used to set up ftp commands.
|
2180
2191
|
*/
|
2181
|
-
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
2192
|
+
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
2182
2193
|
struct curl_slist **list;
|
2183
2194
|
VALUE ftp_command_string;
|
2184
2195
|
Data_Get_Struct(wrap, struct curl_slist *, list);
|
@@ -2192,7 +2203,7 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
|
2192
2203
|
/***********************************************
|
2193
2204
|
* This is an rb_iterate callback used to set up the resolve list.
|
2194
2205
|
*/
|
2195
|
-
static VALUE cb_each_resolve(VALUE resolve, VALUE wrap) {
|
2206
|
+
static VALUE cb_each_resolve(VALUE resolve, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
2196
2207
|
struct curl_slist **list;
|
2197
2208
|
VALUE resolve_string;
|
2198
2209
|
Data_Get_Struct(wrap, struct curl_slist *, list);
|
@@ -2591,7 +2602,7 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2591
2602
|
}
|
2592
2603
|
|
2593
2604
|
// set values on cleanup to nil
|
2594
|
-
rb_easy_del("multi");
|
2605
|
+
//rb_easy_del("multi");
|
2595
2606
|
|
2596
2607
|
return Qnil;
|
2597
2608
|
}
|
@@ -2607,6 +2618,8 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
2607
2618
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2608
2619
|
curl = rbce->curl;
|
2609
2620
|
|
2621
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2622
|
+
|
2610
2623
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
2611
2624
|
|
2612
2625
|
retval = rb_funcall(self, rb_intern("perform"), 0);
|
@@ -2672,6 +2685,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2672
2685
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2673
2686
|
curl = rbce->curl;
|
2674
2687
|
|
2688
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2689
|
+
|
2675
2690
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2676
2691
|
|
2677
2692
|
if (rbce->multipart_form_post) {
|
@@ -2743,6 +2758,8 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2743
2758
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2744
2759
|
curl = rbce->curl;
|
2745
2760
|
|
2761
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2762
|
+
|
2746
2763
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2747
2764
|
ruby_curl_easy_put_data_set(self, data);
|
2748
2765
|
|
@@ -2761,6 +2778,10 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2761
2778
|
* your own body handler, this string will be empty.
|
2762
2779
|
*/
|
2763
2780
|
static VALUE ruby_curl_easy_body_str_get(VALUE self) {
|
2781
|
+
/*
|
2782
|
+
TODO: can we force_encoding on the return here if we see charset=utf-8 in the content-type header?
|
2783
|
+
Content-Type: application/json; charset=utf-8
|
2784
|
+
*/
|
2764
2785
|
CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
|
2765
2786
|
}
|
2766
2787
|
|
@@ -2955,7 +2976,7 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
2955
2976
|
* Retrieve the time, in seconds, it took from the start until the SSL/SSH
|
2956
2977
|
* connect/handshake to the remote host was completed. This time is most often
|
2957
2978
|
* very near to the pre transfer time, except for cases such as HTTP
|
2958
|
-
*
|
2979
|
+
* pipelining where the pretransfer time can be delayed due to waits in line
|
2959
2980
|
* for the pipeline and more.
|
2960
2981
|
*/
|
2961
2982
|
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
@@ -3448,6 +3469,21 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3448
3469
|
return LONG2NUM(rbce->last_result);
|
3449
3470
|
}
|
3450
3471
|
|
3472
|
+
/*
|
3473
|
+
* call-seq:
|
3474
|
+
* easy.last_error => "Error details" or nil
|
3475
|
+
*/
|
3476
|
+
static VALUE ruby_curl_easy_last_error(VALUE self) {
|
3477
|
+
ruby_curl_easy *rbce;
|
3478
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
3479
|
+
|
3480
|
+
if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
|
3481
|
+
return rb_str_new2(rbce->err_buf);
|
3482
|
+
} else {
|
3483
|
+
return Qnil;
|
3484
|
+
}
|
3485
|
+
}
|
3486
|
+
|
3451
3487
|
/*
|
3452
3488
|
* call-seq:
|
3453
3489
|
* easy.setopt Fixnum, value => value
|
@@ -3546,6 +3582,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3546
3582
|
case CURLOPT_TCP_NODELAY: {
|
3547
3583
|
curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
|
3548
3584
|
} break;
|
3585
|
+
case CURLOPT_RANGE: {
|
3586
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
|
3587
|
+
} break;
|
3549
3588
|
case CURLOPT_RESUME_FROM: {
|
3550
3589
|
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
|
3551
3590
|
} break;
|
@@ -3606,6 +3645,20 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3606
3645
|
GetOpenFile(val, open_f_ptr);
|
3607
3646
|
curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
|
3608
3647
|
break;
|
3648
|
+
case CURLOPT_PROTOCOLS:
|
3649
|
+
case CURLOPT_REDIR_PROTOCOLS:
|
3650
|
+
curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
|
3651
|
+
break;
|
3652
|
+
#if HAVE_CURLOPT_SSL_SESSIONID_CACHE
|
3653
|
+
case CURLOPT_SSL_SESSIONID_CACHE:
|
3654
|
+
curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
|
3655
|
+
break;
|
3656
|
+
#endif
|
3657
|
+
#if HAVE_CURLOPT_PROXY_SSL_VERIFYHOST
|
3658
|
+
case CURLOPT_PROXY_SSL_VERIFYHOST:
|
3659
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROXY_SSL_VERIFYHOST, NUM2LONG(val));
|
3660
|
+
break;
|
3661
|
+
#endif
|
3609
3662
|
default:
|
3610
3663
|
rb_raise(rb_eTypeError, "Curb unsupported option");
|
3611
3664
|
}
|
@@ -3722,6 +3775,7 @@ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
|
|
3722
3775
|
}
|
3723
3776
|
|
3724
3777
|
/* =================== INIT LIB =====================*/
|
3778
|
+
// TODO: https://bugs.ruby-lang.org/issues/18007
|
3725
3779
|
void init_curb_easy() {
|
3726
3780
|
idCall = rb_intern("call");
|
3727
3781
|
idJoin = rb_intern("join");
|
@@ -3867,6 +3921,7 @@ void init_curb_easy() {
|
|
3867
3921
|
|
3868
3922
|
rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
|
3869
3923
|
rb_define_method(cCurlEasy, "response_code", ruby_curl_easy_response_code_get, 0);
|
3924
|
+
rb_define_method(cCurlEasy, "code", ruby_curl_easy_response_code_get, 0);
|
3870
3925
|
#if defined(HAVE_CURLINFO_PRIMARY_IP)
|
3871
3926
|
rb_define_method(cCurlEasy, "primary_ip", ruby_curl_easy_primary_ip_get, 0);
|
3872
3927
|
#endif
|
@@ -3913,6 +3968,7 @@ void init_curb_easy() {
|
|
3913
3968
|
rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
|
3914
3969
|
rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
|
3915
3970
|
rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
|
3971
|
+
rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
|
3916
3972
|
|
3917
3973
|
rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
|
3918
3974
|
rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
|
data/ext/curb_easy.h
CHANGED
@@ -36,6 +36,9 @@ typedef struct {
|
|
36
36
|
/* The handler */
|
37
37
|
CURL *curl;
|
38
38
|
|
39
|
+
/* Buffer for error details from CURLOPT_ERRORBUFFER */
|
40
|
+
char err_buf[CURL_ERROR_SIZE];
|
41
|
+
|
39
42
|
VALUE opts; /* rather then allocate everything we might need to store, allocate a Hash and only store objects we actually use... */
|
40
43
|
VALUE multi; /* keep a multi handle alive for each easy handle not being used by a multi handle. This improves easy performance when not within a multi context */
|
41
44
|
|
data/ext/curb_macros.h
CHANGED
@@ -156,4 +156,16 @@
|
|
156
156
|
#define CURB_DEFINE(name) \
|
157
157
|
rb_define_const(mCurl, #name, LONG2NUM(name))
|
158
158
|
|
159
|
+
/* copy and raise exception */
|
160
|
+
#define CURB_CHECK_RB_CALLBACK_RAISE(did_raise) \
|
161
|
+
VALUE exception = rb_hash_aref(did_raise, rb_easy_hkey("error")); \
|
162
|
+
if (FIX2INT(rb_hash_size(did_raise)) > 0 && exception != Qnil) { \
|
163
|
+
rb_hash_clear(did_raise); \
|
164
|
+
VALUE message = rb_funcall(exception, rb_intern("message"), 0); \
|
165
|
+
VALUE aborted_exception = rb_exc_new_str(eCurlErrAbortedByCallback, message); \
|
166
|
+
VALUE backtrace = rb_funcall(exception, rb_intern("backtrace"), 0); \
|
167
|
+
rb_funcall(aborted_exception, rb_intern("set_backtrace"), 1, backtrace); \
|
168
|
+
rb_exc_raise(aborted_exception); \
|
169
|
+
}
|
170
|
+
|
159
171
|
#endif
|
data/ext/curb_multi.c
CHANGED
@@ -43,8 +43,25 @@ static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy);
|
|
43
43
|
static void rb_curl_multi_read_info(VALUE self, CURLM *mptr);
|
44
44
|
static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running);
|
45
45
|
|
46
|
-
static VALUE callback_exception(VALUE
|
47
|
-
|
46
|
+
static VALUE callback_exception(VALUE did_raise, VALUE exception) {
|
47
|
+
// TODO: we could have an option to enable exception reporting
|
48
|
+
/* VALUE ret = rb_funcall(exception, rb_intern("message"), 0);
|
49
|
+
VALUE trace = rb_funcall(exception, rb_intern("backtrace"), 0);
|
50
|
+
if (RB_TYPE_P(trace, T_ARRAY) && RARRAY_LEN(trace) > 0) {
|
51
|
+
printf("we got an exception: %s:%d\n", StringValueCStr(ret), RARRAY_LEN(trace));
|
52
|
+
VALUE sep = rb_str_new_cstr("\n");
|
53
|
+
VALUE trace_lines = rb_ary_join(trace, sep);
|
54
|
+
if (RB_TYPE_P(trace_lines, T_STRING)) {
|
55
|
+
printf("%s\n", StringValueCStr(trace_lines));
|
56
|
+
} else {
|
57
|
+
printf("trace is not a string??\n");
|
58
|
+
}
|
59
|
+
} else {
|
60
|
+
printf("we got an exception: %s\nno stack available\n", StringValueCStr(ret));
|
61
|
+
}
|
62
|
+
*/
|
63
|
+
rb_hash_aset(did_raise, rb_easy_hkey("error"), exception);
|
64
|
+
return exception;
|
48
65
|
}
|
49
66
|
|
50
67
|
void curl_multi_free(ruby_curl_multi *rbcm) {
|
@@ -64,7 +81,7 @@ static void ruby_curl_multi_init(ruby_curl_multi *rbcm) {
|
|
64
81
|
|
65
82
|
/*
|
66
83
|
* call-seq:
|
67
|
-
* Curl::Multi.new =>
|
84
|
+
* Curl::Multi.new => #<Curl::Easy...>
|
68
85
|
*
|
69
86
|
* Create a new Curl::Multi instance
|
70
87
|
*/
|
@@ -132,7 +149,7 @@ VALUE ruby_curl_multi_get_autoclose(VALUE klass) {
|
|
132
149
|
|
133
150
|
/*
|
134
151
|
* call-seq:
|
135
|
-
* multi.requests => [
|
152
|
+
* multi.requests => [#<Curl::Easy...>, ...]
|
136
153
|
*
|
137
154
|
* Returns an array containing all the active requests on this Curl::Multi object.
|
138
155
|
*/
|
@@ -274,7 +291,7 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
274
291
|
long response_code = -1;
|
275
292
|
VALUE easy;
|
276
293
|
ruby_curl_easy *rbce = NULL;
|
277
|
-
VALUE callargs
|
294
|
+
VALUE callargs;
|
278
295
|
|
279
296
|
CURLcode ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (char**)&easy);
|
280
297
|
|
@@ -295,55 +312,62 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
295
312
|
raise_curl_easy_error_exception(ecode);
|
296
313
|
}
|
297
314
|
|
315
|
+
VALUE did_raise = rb_hash_new();
|
316
|
+
|
298
317
|
if (!rb_easy_nil("complete_proc")) {
|
299
318
|
callargs = rb_ary_new3(2, rb_easy_get("complete_proc"), easy);
|
300
319
|
rbce->callback_active = 1;
|
301
|
-
|
320
|
+
rb_rescue(call_status_handler1, callargs, callback_exception, did_raise);
|
302
321
|
rbce->callback_active = 0;
|
303
|
-
|
322
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
304
323
|
}
|
305
324
|
|
325
|
+
#ifdef HAVE_CURLINFO_RESPONSE_CODE
|
306
326
|
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
327
|
+
#else
|
328
|
+
// old libcurl
|
329
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CODE, &response_code);
|
330
|
+
#endif
|
331
|
+
long redirect_count;
|
332
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &redirect_count);
|
307
333
|
|
308
334
|
if (result != 0) {
|
309
335
|
if (!rb_easy_nil("failure_proc")) {
|
310
336
|
callargs = rb_ary_new3(3, rb_easy_get("failure_proc"), easy, rb_curl_easy_error(result));
|
311
337
|
rbce->callback_active = 1;
|
312
|
-
|
338
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
313
339
|
rbce->callback_active = 0;
|
314
|
-
|
340
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
315
341
|
}
|
316
|
-
}
|
317
|
-
else if (!rb_easy_nil("success_proc") &&
|
342
|
+
} else if (!rb_easy_nil("success_proc") &&
|
318
343
|
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
319
344
|
/* NOTE: we allow response_code == 0, in the case of non http requests e.g. reading from disk */
|
320
345
|
callargs = rb_ary_new3(2, rb_easy_get("success_proc"), easy);
|
321
346
|
rbce->callback_active = 1;
|
322
|
-
|
347
|
+
rb_rescue(call_status_handler1, callargs, callback_exception, did_raise);
|
323
348
|
rbce->callback_active = 0;
|
324
|
-
|
325
|
-
|
326
|
-
else if (!rb_easy_nil("redirect_proc") &&
|
327
|
-
(response_code >= 300 && response_code < 400)) {
|
349
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
350
|
+
|
351
|
+
} else if (!rb_easy_nil("redirect_proc") && ((response_code >= 300 && response_code < 400) || redirect_count > 0) ) {
|
328
352
|
rbce->callback_active = 1;
|
329
353
|
callargs = rb_ary_new3(3, rb_easy_get("redirect_proc"), easy, rb_curl_easy_error(result));
|
330
354
|
rbce->callback_active = 0;
|
331
|
-
|
332
|
-
|
333
|
-
else if (!rb_easy_nil("missing_proc") &&
|
355
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
356
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
357
|
+
} else if (!rb_easy_nil("missing_proc") &&
|
334
358
|
(response_code >= 400 && response_code < 500)) {
|
335
359
|
rbce->callback_active = 1;
|
336
360
|
callargs = rb_ary_new3(3, rb_easy_get("missing_proc"), easy, rb_curl_easy_error(result));
|
337
361
|
rbce->callback_active = 0;
|
338
|
-
|
339
|
-
|
340
|
-
else if (!rb_easy_nil("failure_proc") &&
|
362
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
363
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
364
|
+
} else if (!rb_easy_nil("failure_proc") &&
|
341
365
|
(response_code >= 500 && response_code <= 999)) {
|
342
366
|
callargs = rb_ary_new3(3, rb_easy_get("failure_proc"), easy, rb_curl_easy_error(result));
|
343
367
|
rbce->callback_active = 1;
|
344
|
-
|
368
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
345
369
|
rbce->callback_active = 0;
|
346
|
-
|
370
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
347
371
|
}
|
348
372
|
|
349
373
|
}
|
@@ -627,6 +651,8 @@ void init_curb_multi() {
|
|
627
651
|
idCall = rb_intern("call");
|
628
652
|
cCurlMulti = rb_define_class_under(mCurl, "Multi", rb_cObject);
|
629
653
|
|
654
|
+
rb_undef_alloc_func(cCurlMulti);
|
655
|
+
|
630
656
|
/* Class methods */
|
631
657
|
rb_define_singleton_method(cCurlMulti, "new", ruby_curl_multi_new, 0);
|
632
658
|
rb_define_singleton_method(cCurlMulti, "default_timeout=", ruby_curl_multi_set_default_timeout, 1);
|