curb 0.9.8 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|