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.
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 => #<Curl::Easy...>
324
- * Curl::Easy.new(url = nil) => #<Curl::Easy...>
325
- * Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
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
- rb_easy_set("url", url);
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 => #&lt;easy clone&gt;
370
- * easy.dup => #&lt;easy clone&gt;
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
- /* rest clobbers the private setting, so reset it to self */
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, VALUE connect_timeout) {
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, VALUE connect_timeout_ms) {
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, VALUE dns_cache_timeout) {
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, VALUE ftp_response_timeout) {
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, VALUE low_speed_limit) {
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, VALUE low_speed_time) {
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, VALUE max_send_speed_large) {
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, VALUE max_recv_speed_large) {
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, VALUE username) {
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, VALUE password) {
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, VALUE ssl_version) {
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, VALUE use_ssl) {
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, VALUE ftp_filemethod) {
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| ... } => &lt;old handler&gt;
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| ... } => &lt;old handler&gt;
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| ... } => &lt;old handler&gt;
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| ... } => &lt;old handler;&gt;
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| ... } => &lt;old handler;&gt;
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| ... } => &lt;old handler&gt;
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| ... } => &lt;old handler&gt;
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| ... } => &lt;old handler&gt;
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| ... } => &lt;old handler&gt;
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
- // This is a bit inefficient, but we don't want to be modifying
2126
- // the actual values in the original hash.
2127
- header_str = rb_str_plus(name, rb_str_new2(": "));
2128
- header_str = rb_str_plus(header_str, value);
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 Qtrue.
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
- * pippelining where the pretransfer time can be delayed due to waits in line
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