curb 0.9.8 → 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 +69 -7
- data/Rakefile +18 -19
- data/ext/banned.h +32 -0
- data/ext/curb.c +164 -8
- data/ext/curb.h +18 -5
- data/ext/curb_easy.c +134 -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 +45 -0
- data/lib/curb.rb +1 -0
- data/lib/curl/easy.rb +14 -7
- data/lib/curl/multi.rb +11 -3
- data/lib/curl.rb +12 -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_issue277.rb +32 -0
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_raise_on_callback.rb +29 -0
- data/tests/helper.rb +27 -1
- data/tests/tc_curl_easy.rb +72 -4
- data/tests/tc_curl_maxfilesize.rb +12 -0
- data/tests/tc_curl_multi.rb +98 -16
- data/tests/tc_curl_postfield.rb +29 -29
- data/tests/tc_curl_protocols.rb +37 -0
- data/tests/timeout.rb +21 -5
- metadata +37 -27
data/ext/curb_easy.c
CHANGED
@@ -25,10 +25,16 @@ static VALUE rbstrAmp;
|
|
25
25
|
|
26
26
|
VALUE cCurlEasy;
|
27
27
|
|
28
|
+
// for Ruby 1.8
|
29
|
+
#ifndef HAVE_RB_IO_STDIO_FILE
|
30
|
+
static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
31
|
+
return fptr->f;
|
32
|
+
}
|
33
|
+
#endif
|
28
34
|
|
29
35
|
/* ================== CURL HANDLER FUNCS ==============*/
|
30
36
|
|
31
|
-
static VALUE callback_exception(VALUE unused) {
|
37
|
+
static VALUE callback_exception(VALUE unused, VALUE exception) {
|
32
38
|
return Qfalse;
|
33
39
|
}
|
34
40
|
|
@@ -247,6 +253,7 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
247
253
|
curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
|
248
254
|
curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
|
249
255
|
curl_easy_cleanup(rbce->curl);
|
256
|
+
rbce->curl = NULL;
|
250
257
|
}
|
251
258
|
}
|
252
259
|
|
@@ -261,6 +268,8 @@ void curl_easy_free(ruby_curl_easy *rbce) {
|
|
261
268
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
262
269
|
rbce->opts = rb_hash_new();
|
263
270
|
|
271
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
272
|
+
|
264
273
|
rbce->curl_headers = NULL;
|
265
274
|
rbce->curl_proxy_headers = NULL;
|
266
275
|
rbce->curl_ftp_commands = NULL;
|
@@ -320,9 +329,9 @@ static VALUE ruby_curl_easy_allocate(VALUE klass) {
|
|
320
329
|
|
321
330
|
/*
|
322
331
|
* call-seq:
|
323
|
-
* Curl::Easy.new =>
|
324
|
-
* Curl::Easy.new(url = nil) =>
|
325
|
-
* 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...>
|
326
335
|
*
|
327
336
|
* Initialize a new Curl::Easy instance, optionally supplying the URL.
|
328
337
|
* The block form allows further configuration to be supplied before
|
@@ -348,8 +357,9 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
348
357
|
|
349
358
|
ruby_curl_easy_zero(rbce);
|
350
359
|
|
351
|
-
|
360
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
352
361
|
|
362
|
+
rb_easy_set("url", url);
|
353
363
|
|
354
364
|
/* set the pointer to the curl handle */
|
355
365
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
|
@@ -366,8 +376,8 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
366
376
|
|
367
377
|
/*
|
368
378
|
* call-seq:
|
369
|
-
* easy.clone =>
|
370
|
-
* easy.dup =>
|
379
|
+
* easy.clone => <easy clone>
|
380
|
+
* easy.dup => <easy clone>
|
371
381
|
*
|
372
382
|
* Clone this Curl::Easy instance, creating a new instance.
|
373
383
|
* This method duplicates the underlying CURL* handle.
|
@@ -385,6 +395,8 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
385
395
|
newrbce->curl_ftp_commands = NULL;
|
386
396
|
newrbce->curl_resolve = NULL;
|
387
397
|
|
398
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
399
|
+
|
388
400
|
return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
|
389
401
|
}
|
390
402
|
|
@@ -454,7 +466,9 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
454
466
|
curl_easy_reset(rbce->curl);
|
455
467
|
ruby_curl_easy_zero(rbce);
|
456
468
|
|
457
|
-
|
469
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
470
|
+
|
471
|
+
/* reset clobbers the private setting, so reset it to self */
|
458
472
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)self);
|
459
473
|
if (ecode != CURLE_OK) {
|
460
474
|
raise_curl_easy_error_exception(ecode);
|
@@ -943,7 +957,7 @@ static VALUE ruby_curl_easy_ftp_commands_set(VALUE self, VALUE ftp_commands) {
|
|
943
957
|
}
|
944
958
|
|
945
959
|
/*
|
946
|
-
* call-seq
|
960
|
+
* call-seq:
|
947
961
|
* easy.ftp_commands => array or nil
|
948
962
|
*/
|
949
963
|
static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
|
@@ -962,7 +976,7 @@ static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
|
|
962
976
|
}
|
963
977
|
|
964
978
|
/*
|
965
|
-
* call-seq
|
979
|
+
* call-seq:
|
966
980
|
* easy.resolve => array or nil
|
967
981
|
*/
|
968
982
|
static VALUE ruby_curl_easy_resolve_get(VALUE self) {
|
@@ -1297,7 +1311,7 @@ static VALUE ruby_curl_easy_connect_timeout_set(VALUE self, VALUE connect_timeou
|
|
1297
1311
|
* Obtain the maximum time in seconds that you allow the connection to the
|
1298
1312
|
* server to take.
|
1299
1313
|
*/
|
1300
|
-
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self
|
1314
|
+
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self) {
|
1301
1315
|
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
|
1302
1316
|
}
|
1303
1317
|
|
@@ -1323,7 +1337,7 @@ static VALUE ruby_curl_easy_connect_timeout_ms_set(VALUE self, VALUE connect_tim
|
|
1323
1337
|
* Obtain the maximum time in milliseconds that you allow the connection to the
|
1324
1338
|
* server to take.
|
1325
1339
|
*/
|
1326
|
-
static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self
|
1340
|
+
static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self) {
|
1327
1341
|
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout_ms, 0);
|
1328
1342
|
}
|
1329
1343
|
|
@@ -1346,7 +1360,7 @@ static VALUE ruby_curl_easy_dns_cache_timeout_set(VALUE self, VALUE dns_cache_ti
|
|
1346
1360
|
*
|
1347
1361
|
* Obtain the dns cache timeout in seconds.
|
1348
1362
|
*/
|
1349
|
-
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self
|
1363
|
+
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self) {
|
1350
1364
|
CURB_IMMED_GETTER(ruby_curl_easy, dns_cache_timeout, -1);
|
1351
1365
|
}
|
1352
1366
|
|
@@ -1373,7 +1387,7 @@ static VALUE ruby_curl_easy_ftp_response_timeout_set(VALUE self, VALUE ftp_respo
|
|
1373
1387
|
*
|
1374
1388
|
* Obtain the maximum time that libcurl will wait for FTP command responses.
|
1375
1389
|
*/
|
1376
|
-
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self
|
1390
|
+
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self) {
|
1377
1391
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
|
1378
1392
|
}
|
1379
1393
|
|
@@ -1396,7 +1410,7 @@ static VALUE ruby_curl_easy_low_speed_limit_set(VALUE self, VALUE low_speed_limi
|
|
1396
1410
|
* Obtain the minimum transfer speed over +low_speed+time+ below which the
|
1397
1411
|
* transfer will be aborted.
|
1398
1412
|
*/
|
1399
|
-
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self
|
1413
|
+
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self) {
|
1400
1414
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_limit, 0);
|
1401
1415
|
}
|
1402
1416
|
|
@@ -1418,7 +1432,7 @@ static VALUE ruby_curl_easy_low_speed_time_set(VALUE self, VALUE low_speed_time)
|
|
1418
1432
|
* Obtain the time that the transfer should be below +low_speed_limit+ for
|
1419
1433
|
* the library to abort it.
|
1420
1434
|
*/
|
1421
|
-
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self
|
1435
|
+
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self) {
|
1422
1436
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
|
1423
1437
|
}
|
1424
1438
|
|
@@ -1438,7 +1452,7 @@ static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_
|
|
1438
1452
|
*
|
1439
1453
|
* Get the maximal sending transfer speed (in bytes per second)
|
1440
1454
|
*/
|
1441
|
-
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) {
|
1442
1456
|
CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
|
1443
1457
|
}
|
1444
1458
|
|
@@ -1458,7 +1472,7 @@ static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_
|
|
1458
1472
|
*
|
1459
1473
|
* Get the maximal receiving transfer speed (in bytes per second)
|
1460
1474
|
*/
|
1461
|
-
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) {
|
1462
1476
|
CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
1463
1477
|
}
|
1464
1478
|
|
@@ -1482,7 +1496,7 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
|
|
1482
1496
|
*
|
1483
1497
|
* Get the current username
|
1484
1498
|
*/
|
1485
|
-
static VALUE ruby_curl_easy_username_get(VALUE self
|
1499
|
+
static VALUE ruby_curl_easy_username_get(VALUE self) {
|
1486
1500
|
#if HAVE_CURLOPT_USERNAME
|
1487
1501
|
CURB_OBJECT_HGETTER(ruby_curl_easy, username);
|
1488
1502
|
#else
|
@@ -1510,7 +1524,7 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
|
|
1510
1524
|
*
|
1511
1525
|
* Get the current password
|
1512
1526
|
*/
|
1513
|
-
static VALUE ruby_curl_easy_password_get(VALUE self
|
1527
|
+
static VALUE ruby_curl_easy_password_get(VALUE self) {
|
1514
1528
|
#if HAVE_CURLOPT_PASSWORD
|
1515
1529
|
CURB_OBJECT_HGETTER(ruby_curl_easy, password);
|
1516
1530
|
#else
|
@@ -1532,6 +1546,7 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
|
|
1532
1546
|
* Curl::CURL_SSLVERSION_TLSv1_0
|
1533
1547
|
* Curl::CURL_SSLVERSION_TLSv1_1
|
1534
1548
|
* Curl::CURL_SSLVERSION_TLSv1_2
|
1549
|
+
* Curl::CURL_SSLVERSION_TLSv1_3
|
1535
1550
|
*/
|
1536
1551
|
static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
1537
1552
|
CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
|
@@ -1543,7 +1558,7 @@ static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
|
1543
1558
|
*
|
1544
1559
|
* Get the version of SSL/TLS that libcurl will attempt to use.
|
1545
1560
|
*/
|
1546
|
-
static VALUE ruby_curl_easy_ssl_version_get(VALUE self
|
1561
|
+
static VALUE ruby_curl_easy_ssl_version_get(VALUE self) {
|
1547
1562
|
CURB_IMMED_GETTER(ruby_curl_easy, ssl_version, -1);
|
1548
1563
|
}
|
1549
1564
|
|
@@ -1564,7 +1579,7 @@ static VALUE ruby_curl_easy_use_ssl_set(VALUE self, VALUE use_ssl) {
|
|
1564
1579
|
*
|
1565
1580
|
* Get the desired level for using SSL on FTP connections.
|
1566
1581
|
*/
|
1567
|
-
static VALUE ruby_curl_easy_use_ssl_get(VALUE self
|
1582
|
+
static VALUE ruby_curl_easy_use_ssl_get(VALUE self) {
|
1568
1583
|
CURB_IMMED_GETTER(ruby_curl_easy, use_ssl, -1);
|
1569
1584
|
}
|
1570
1585
|
|
@@ -1580,12 +1595,12 @@ static VALUE ruby_curl_easy_ftp_filemethod_set(VALUE self, VALUE ftp_filemethod)
|
|
1580
1595
|
}
|
1581
1596
|
|
1582
1597
|
/*
|
1583
|
-
* call-seq
|
1598
|
+
* call-seq:
|
1584
1599
|
* easy.ftp_filemethod => fixnum
|
1585
1600
|
*
|
1586
1601
|
* Get the configuration for how libcurl will reach files on the server.
|
1587
1602
|
*/
|
1588
|
-
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self
|
1603
|
+
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self) {
|
1589
1604
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_filemethod, -1);
|
1590
1605
|
}
|
1591
1606
|
|
@@ -1952,7 +1967,7 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
1952
1967
|
|
1953
1968
|
/*
|
1954
1969
|
* call-seq:
|
1955
|
-
* easy.on_body { |body_data| ... } =>
|
1970
|
+
* easy.on_body { |body_data| ... } => <old handler>
|
1956
1971
|
*
|
1957
1972
|
* Assign or remove the +on_body+ handler for this Curl::Easy instance.
|
1958
1973
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1971,7 +1986,7 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
|
|
1971
1986
|
|
1972
1987
|
/*
|
1973
1988
|
* call-seq:
|
1974
|
-
* easy.on_success { |easy| ... } =>
|
1989
|
+
* easy.on_success { |easy| ... } => <old handler>
|
1975
1990
|
*
|
1976
1991
|
* Assign or remove the +on_success+ handler for this Curl::Easy instance.
|
1977
1992
|
* To remove a previously-supplied handler, call this method with no
|
@@ -1986,7 +2001,7 @@ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
|
|
1986
2001
|
|
1987
2002
|
/*
|
1988
2003
|
* call-seq:
|
1989
|
-
* easy.on_failure {|easy,code| ... } =>
|
2004
|
+
* easy.on_failure {|easy,code| ... } => <old handler>
|
1990
2005
|
*
|
1991
2006
|
* Assign or remove the +on_failure+ handler for this Curl::Easy instance.
|
1992
2007
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2001,7 +2016,7 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
|
|
2001
2016
|
|
2002
2017
|
/*
|
2003
2018
|
* call-seq:
|
2004
|
-
* easy.on_missing {|easy,code| ... } =>
|
2019
|
+
* easy.on_missing {|easy,code| ... } => <old handler;>
|
2005
2020
|
*
|
2006
2021
|
* Assign or remove the on_missing handler for this Curl::Easy instance.
|
2007
2022
|
* To remove a previously-supplied handler, call this method with no attached
|
@@ -2016,7 +2031,7 @@ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
2016
2031
|
|
2017
2032
|
/*
|
2018
2033
|
* call-seq:
|
2019
|
-
* easy.on_redirect {|easy,code| ... } =>
|
2034
|
+
* easy.on_redirect {|easy,code| ... } => <old handler;>
|
2020
2035
|
*
|
2021
2036
|
* Assign or remove the on_redirect handler for this Curl::Easy instance.
|
2022
2037
|
* To remove a previously-supplied handler, call this method with no attached
|
@@ -2031,7 +2046,7 @@ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
2031
2046
|
|
2032
2047
|
/*
|
2033
2048
|
* call-seq:
|
2034
|
-
* easy.on_complete {|easy| ... } =>
|
2049
|
+
* easy.on_complete {|easy| ... } => <old handler>
|
2035
2050
|
*
|
2036
2051
|
* Assign or remove the +on_complete+ handler for this Curl::Easy instance.
|
2037
2052
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2045,7 +2060,7 @@ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
|
|
2045
2060
|
|
2046
2061
|
/*
|
2047
2062
|
* call-seq:
|
2048
|
-
* easy.on_header { |header_data| ... } =>
|
2063
|
+
* easy.on_header { |header_data| ... } => <old handler>
|
2049
2064
|
*
|
2050
2065
|
* Assign or remove the +on_header+ handler for this Curl::Easy instance.
|
2051
2066
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2061,7 +2076,7 @@ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
|
|
2061
2076
|
|
2062
2077
|
/*
|
2063
2078
|
* call-seq:
|
2064
|
-
* 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>
|
2065
2080
|
*
|
2066
2081
|
* Assign or remove the +on_progress+ handler for this Curl::Easy instance.
|
2067
2082
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2082,7 +2097,7 @@ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
|
|
2082
2097
|
|
2083
2098
|
/*
|
2084
2099
|
* call-seq:
|
2085
|
-
* easy.on_debug { |type, data| ... } =>
|
2100
|
+
* easy.on_debug { |type, data| ... } => <old handler>
|
2086
2101
|
*
|
2087
2102
|
* Assign or remove the +on_debug+ handler for this Curl::Easy instance.
|
2088
2103
|
* To remove a previously-supplied handler, call this method with no
|
@@ -2107,7 +2122,7 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
|
|
2107
2122
|
/***********************************************
|
2108
2123
|
* This is an rb_iterate callback used to set up http headers.
|
2109
2124
|
*/
|
2110
|
-
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) {
|
2111
2126
|
struct curl_slist **list;
|
2112
2127
|
VALUE header_str = Qnil;
|
2113
2128
|
|
@@ -2121,11 +2136,14 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
2121
2136
|
|
2122
2137
|
name = rb_obj_as_string(rb_ary_entry(header, 0));
|
2123
2138
|
value = rb_obj_as_string(rb_ary_entry(header, 1));
|
2124
|
-
|
2125
|
-
|
2126
|
-
|
2127
|
-
|
2128
|
-
|
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
|
+
}
|
2129
2147
|
} else {
|
2130
2148
|
header_str = rb_obj_as_string(header);
|
2131
2149
|
}
|
@@ -2139,7 +2157,7 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
2139
2157
|
/***********************************************
|
2140
2158
|
* This is an rb_iterate callback used to set up http proxy headers.
|
2141
2159
|
*/
|
2142
|
-
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) {
|
2143
2161
|
struct curl_slist **list;
|
2144
2162
|
VALUE proxy_header_str = Qnil;
|
2145
2163
|
|
@@ -2171,7 +2189,7 @@ static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap) {
|
|
2171
2189
|
/***********************************************
|
2172
2190
|
* This is an rb_iterate callback used to set up ftp commands.
|
2173
2191
|
*/
|
2174
|
-
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) {
|
2175
2193
|
struct curl_slist **list;
|
2176
2194
|
VALUE ftp_command_string;
|
2177
2195
|
Data_Get_Struct(wrap, struct curl_slist *, list);
|
@@ -2185,7 +2203,7 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
|
2185
2203
|
/***********************************************
|
2186
2204
|
* This is an rb_iterate callback used to set up the resolve list.
|
2187
2205
|
*/
|
2188
|
-
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) {
|
2189
2207
|
struct curl_slist **list;
|
2190
2208
|
VALUE resolve_string;
|
2191
2209
|
Data_Get_Struct(wrap, struct curl_slist *, list);
|
@@ -2543,7 +2561,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
2543
2561
|
*
|
2544
2562
|
* Clean up a connection
|
2545
2563
|
*
|
2546
|
-
* Always returns
|
2564
|
+
* Always returns Qnil.
|
2547
2565
|
*/
|
2548
2566
|
VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
2549
2567
|
|
@@ -2583,6 +2601,9 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2583
2601
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
2584
2602
|
}
|
2585
2603
|
|
2604
|
+
// set values on cleanup to nil
|
2605
|
+
//rb_easy_del("multi");
|
2606
|
+
|
2586
2607
|
return Qnil;
|
2587
2608
|
}
|
2588
2609
|
|
@@ -2597,6 +2618,8 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
2597
2618
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2598
2619
|
curl = rbce->curl;
|
2599
2620
|
|
2621
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2622
|
+
|
2600
2623
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
2601
2624
|
|
2602
2625
|
retval = rb_funcall(self, rb_intern("perform"), 0);
|
@@ -2662,6 +2685,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2662
2685
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2663
2686
|
curl = rbce->curl;
|
2664
2687
|
|
2688
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2689
|
+
|
2665
2690
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2666
2691
|
|
2667
2692
|
if (rbce->multipart_form_post) {
|
@@ -2733,6 +2758,8 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2733
2758
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2734
2759
|
curl = rbce->curl;
|
2735
2760
|
|
2761
|
+
memset(rbce->err_buf, 0, sizeof(rbce->err_buf));
|
2762
|
+
|
2736
2763
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2737
2764
|
ruby_curl_easy_put_data_set(self, data);
|
2738
2765
|
|
@@ -2751,6 +2778,10 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2751
2778
|
* your own body handler, this string will be empty.
|
2752
2779
|
*/
|
2753
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
|
+
*/
|
2754
2785
|
CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
|
2755
2786
|
}
|
2756
2787
|
|
@@ -2945,7 +2976,7 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
2945
2976
|
* Retrieve the time, in seconds, it took from the start until the SSL/SSH
|
2946
2977
|
* connect/handshake to the remote host was completed. This time is most often
|
2947
2978
|
* very near to the pre transfer time, except for cases such as HTTP
|
2948
|
-
*
|
2979
|
+
* pipelining where the pretransfer time can be delayed due to waits in line
|
2949
2980
|
* for the pipeline and more.
|
2950
2981
|
*/
|
2951
2982
|
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
@@ -3438,6 +3469,21 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3438
3469
|
return LONG2NUM(rbce->last_result);
|
3439
3470
|
}
|
3440
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
|
+
|
3441
3487
|
/*
|
3442
3488
|
* call-seq:
|
3443
3489
|
* easy.setopt Fixnum, value => value
|
@@ -3447,6 +3493,7 @@ static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3447
3493
|
static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
3448
3494
|
ruby_curl_easy *rbce;
|
3449
3495
|
long option = NUM2LONG(opt);
|
3496
|
+
rb_io_t *open_f_ptr;
|
3450
3497
|
|
3451
3498
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
3452
3499
|
|
@@ -3535,6 +3582,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3535
3582
|
case CURLOPT_TCP_NODELAY: {
|
3536
3583
|
curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
|
3537
3584
|
} break;
|
3585
|
+
case CURLOPT_RANGE: {
|
3586
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
|
3587
|
+
} break;
|
3538
3588
|
case CURLOPT_RESUME_FROM: {
|
3539
3589
|
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
|
3540
3590
|
} break;
|
@@ -3571,6 +3621,43 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3571
3621
|
case CURLOPT_MAXFILESIZE:
|
3572
3622
|
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
|
3573
3623
|
break;
|
3624
|
+
#endif
|
3625
|
+
#if HAVE_CURLOPT_TCP_KEEPALIVE
|
3626
|
+
case CURLOPT_TCP_KEEPALIVE:
|
3627
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
|
3628
|
+
break;
|
3629
|
+
case CURLOPT_TCP_KEEPIDLE:
|
3630
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
|
3631
|
+
break;
|
3632
|
+
case CURLOPT_TCP_KEEPINTVL:
|
3633
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
|
3634
|
+
break;
|
3635
|
+
#endif
|
3636
|
+
#if HAVE_CURLOPT_HAPROXYPROTOCOL
|
3637
|
+
case CURLOPT_HAPROXYPROTOCOL:
|
3638
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
|
3639
|
+
break;
|
3640
|
+
#endif
|
3641
|
+
case CURLOPT_STDERR:
|
3642
|
+
// libcurl requires raw FILE pointer and this should be IO object in Ruby.
|
3643
|
+
// Tempfile or StringIO won't work.
|
3644
|
+
Check_Type(val, T_FILE);
|
3645
|
+
GetOpenFile(val, open_f_ptr);
|
3646
|
+
curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
|
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;
|
3574
3661
|
#endif
|
3575
3662
|
default:
|
3576
3663
|
rb_raise(rb_eTypeError, "Curb unsupported option");
|
@@ -3688,6 +3775,7 @@ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
|
|
3688
3775
|
}
|
3689
3776
|
|
3690
3777
|
/* =================== INIT LIB =====================*/
|
3778
|
+
// TODO: https://bugs.ruby-lang.org/issues/18007
|
3691
3779
|
void init_curb_easy() {
|
3692
3780
|
idCall = rb_intern("call");
|
3693
3781
|
idJoin = rb_intern("join");
|
@@ -3833,6 +3921,7 @@ void init_curb_easy() {
|
|
3833
3921
|
|
3834
3922
|
rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
|
3835
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);
|
3836
3925
|
#if defined(HAVE_CURLINFO_PRIMARY_IP)
|
3837
3926
|
rb_define_method(cCurlEasy, "primary_ip", ruby_curl_easy_primary_ip_get, 0);
|
3838
3927
|
#endif
|
@@ -3879,6 +3968,7 @@ void init_curb_easy() {
|
|
3879
3968
|
rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
|
3880
3969
|
rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
|
3881
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);
|
3882
3972
|
|
3883
3973
|
rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
|
3884
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
|