curb 1.3.6 → 1.3.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11348a158e7da3d3406acd021be1a15f881ce2c607ff04e60b522a3bd92cd828
4
- data.tar.gz: 0c524ce914df77b109a2aad85289386b2bf54028733fcf4ec5657a84abf511b8
3
+ metadata.gz: 12fe9b3726ab9e6bb2a7369ebae117d8a2da19db382acd1b182af4b8cd19d4cb
4
+ data.tar.gz: 05a07a992383c5c956d037770215bb2bb8795cc3062bad6ca2ec84c0389dd880
5
5
  SHA512:
6
- metadata.gz: b4ebd6b04943bfc099a6593ede1c70298555ed1a6613958e8628cde43c30b8c7f8b86990d91c7a350481589495fe7d5dc4ad1ac3c313823bb7fb21e483e8910c
7
- data.tar.gz: 0a78bc41496259eae9989d25e4a47c57a9a9aed6f79b00e77efae691b487a730e71e6cdf8081ae35d33893a84b033219ae24c40cf47effd8e3d1b0ca3591f222
6
+ metadata.gz: 3f0016de5762e46f6b1f1ef3a588c82a41a8a3b1f8a3d3f351626279fa053539ec7d6ca35a8a9792ed5c9dd6e06c550d2b9ba7b900cffbb60af09f260e603662
7
+ data.tar.gz: c26cfe8e0c03bf30dda075c6abb916e4e1d66205f61ebe54d2db73c1359e3c8def512163393280874730769ffad6fc96c24aad8e5f79a5d586e1b43640ed6b9f
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # Curb - Libcurl bindings for Ruby
2
2
 
3
- [![CI](https://github.com/taf2/curb/actions/workflows/ci.yml/badge.svg)](https://github.com/taf2/curb/actions/workflows/ci.yml)
4
- [![codecov](https://codecov.io/gh/taf2/curb/branch/master/graph/badge.svg)](https://codecov.io/gh/taf2/curb)
3
+ [![CI](https://github.com/taf2/curb/actions/workflows/CI.yml/badge.svg)](https://github.com/taf2/curb/actions/workflows/CI.yml)
5
4
  [![Gem Version](https://badge.fury.io/rb/curb.svg)](https://badge.fury.io/rb/curb)
6
5
 
7
- * [CI Build Status](https://github.com/taf2/curb/actions/workflows/ci.yml)
6
+ * [CI Build Status](https://github.com/taf2/curb/actions/workflows/CI.yml)
8
7
  * [rubydoc rdoc](http://www.rubydoc.info/github/taf2/curb/)
9
8
  * [github project](http://github.com/taf2/curb/tree/master)
10
9
 
@@ -23,8 +22,8 @@ Ruby license. See the LICENSE file for the gory details.
23
22
 
24
23
  ## Easy mode
25
24
 
26
- GET request
27
- ```
25
+ ### GET request
26
+ ```ruby
28
27
  res = Curl.get("https://www.google.com/") {|http|
29
28
  http.timeout = 10 # raise exception if request/response not handled within 10 seconds
30
29
  }
@@ -33,8 +32,8 @@ GET request
33
32
  puts res.body
34
33
  ```
35
34
 
36
- POST request
37
- ```
35
+ ### POST request
36
+ ```ruby
38
37
  res = Curl.post("https://your-server.com/endpoint", {post: "this"}.to_json) {|http|
39
38
  http.headers["Content-Type"] = "application/json"
40
39
  }
@@ -45,7 +44,9 @@ POST request
45
44
 
46
45
  ## FTP Support
47
46
 
47
+ ```ruby
48
48
  require 'curb'
49
+ ```
49
50
 
50
51
  ### Basic FTP Download
51
52
  ```ruby
@@ -139,7 +140,7 @@ puts list.body
139
140
  ```
140
141
 
141
142
  ### Advanced FTP Usage with Various Options
142
- ```
143
+ ```ruby
143
144
  puts "\n=== Advanced FTP Example ==="
144
145
  advanced = Curl::Easy.new do |curl|
145
146
  curl.url = 'ftp://ftp.example.com/remote/file.txt'
@@ -175,7 +176,7 @@ advanced.perform
175
176
  ```
176
177
 
177
178
  ### Parallel FTP Downloads
178
- ```
179
+ ```ruby
179
180
  puts "\n=== Parallel FTP Downloads Example ==="
180
181
  urls = [
181
182
  'ftp://ftp.example.com/file1.txt',
@@ -185,7 +186,7 @@ urls = [
185
186
  ```
186
187
 
187
188
  ### Common options for all connections
188
- ```
189
+ ```ruby
189
190
  options = {
190
191
  :username => 'user',
191
192
  :password => 'password',
@@ -260,7 +261,7 @@ custom body callbacks.
260
261
 
261
262
  * A working Ruby installation (`2.0.0+` will work but `2.1+` preferred) (it's possible it still works with 1.8.7 but you'd have to tell me if not...)
262
263
  * A working libcurl development installation
263
- (Ideally one of the versions listed in the compatibility chart below that maps to your `curb` version)
264
+ (Ideally one of the versions listed in the compatibility chart below that maps to your `curb` version)
264
265
  * A sane build environment (e.g. gcc, make)
265
266
 
266
267
  ## Version Compatibility chart
@@ -269,8 +270,27 @@ A **non-exhaustive** set of compatibility versions of the libcurl library
269
270
  with this gem are as follows. (Note that these are only the ones that have been
270
271
  tested and reported to work across a variety of platforms / rubies)
271
272
 
273
+ The upper bounds for recent releases reflect the compatibility work documented
274
+ in the changelog, including the libcurl 8.16.0 regression workaround in 1.2.2
275
+ and the libcurl 8.20.0 scheduler fixes in 1.3.5. The 1.3.7 upper bound also
276
+ includes expected compatibility with libcurl 8.21.0; this version is not yet
277
+ an explicit CI target.
278
+
272
279
  | Gem Version | Release Date | libcurl versions |
273
280
  | ----------- | -------------- | ----------------- |
281
+ | 1.3.7 | Jul 10, 2026 | 7.58 – 8.21.0 |
282
+ | 1.3.6 | Jun 17, 2026 | 7.58 – 8.20.0 |
283
+ | 1.3.5 | May 14, 2026 | 7.58 – 8.20.0 |
284
+ | 1.3.4 | May 12, 2026 | 7.58 – 8.16.0 |
285
+ | 1.3.3 | May 11, 2026 | 7.58 – 8.16.0 |
286
+ | 1.3.2 | Apr 23, 2026 | 7.58 – 8.16.0 |
287
+ | 1.3.1 | Apr 05, 2026 | 7.58 – 8.16.0 |
288
+ | 1.3.0 | Apr 02, 2026 | 7.58 – 8.16.0 |
289
+ | 1.2.2 | Sep 18, 2025 | 7.58 – 8.16.0 |
290
+ | 1.2.1 | Sep 17, 2025 | 7.58 – 8.12.1 |
291
+ | 1.2.0 | Aug 31, 2025 | 7.58 – 8.12.1 |
292
+ | 1.1.0 | Jul 24, 2025 | 7.58 – 8.12.1 |
293
+ | 1.0.9 | Feb 15, 2025 | 7.58 – 8.12.1 |
274
294
  | 1.0.8 | Feb 10, 2025 | 7.58 – 8.12.1 |
275
295
  | 1.0.7 | Feb 09, 2025 | 7.58 – 8.12.1 |
276
296
  | 1.0.6 | Aug 23, 2024 | 7.58 – 8.12.1 |
@@ -287,7 +307,7 @@ tested and reported to work across a variety of platforms / rubies)
287
307
  | 0.9.4 | Aug 2017 | 7.41 – 7.58 |
288
308
  | 0.9.3 | Apr 2016 | 7.26 – 7.58 |
289
309
 
290
- ```*avoid using these version are known to have issues with segmentation faults```
310
+ *Avoid using these versions; they are known to have issues with segmentation faults.*
291
311
 
292
312
  ## Installation...
293
313
 
@@ -457,6 +477,7 @@ c = Curl::Easy.http_post("http://my.rails.box/thing/create",
457
477
  c = Curl::Easy.new("http://my.rails.box/files/upload")
458
478
  c.multipart_form_post = true
459
479
  c.http_post(Curl::PostField.file('thing[file]', 'myfile.rb'))
480
+ ```
460
481
 
461
482
  ### Custom request target
462
483
 
@@ -470,7 +491,6 @@ c.perform
470
491
  ```
471
492
 
472
493
  For HTTPS, prefer `easy.resolve = ["host:443:IP"]` to keep Host/SNI/certificates aligned.
473
- ```
474
494
 
475
495
  ### Using HTTP/2
476
496
 
data/ext/curb.c CHANGED
@@ -748,6 +748,15 @@ void Init_curb_core() {
748
748
  #ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
749
749
  CURB_DEFINE(CURLOPT_FTP_CREATE_MISSING_DIRS);
750
750
  #endif
751
+ #ifdef HAVE_CURLFTP_CREATE_DIR_NONE
752
+ CURB_DEFINE(CURLFTP_CREATE_DIR_NONE);
753
+ #endif
754
+ #ifdef HAVE_CURLFTP_CREATE_DIR
755
+ CURB_DEFINE(CURLFTP_CREATE_DIR);
756
+ #endif
757
+ #ifdef HAVE_CURLFTP_CREATE_DIR_RETRY
758
+ CURB_DEFINE(CURLFTP_CREATE_DIR_RETRY);
759
+ #endif
751
760
  #ifdef HAVE_CURLOPT_FTP_RESPONSE_TIMEOUT
752
761
  CURB_DEFINE(CURLOPT_FTP_RESPONSE_TIMEOUT);
753
762
  #endif
data/ext/curb.h CHANGED
@@ -28,11 +28,11 @@
28
28
  #include "curb_macros.h"
29
29
 
30
30
  // These should be managed from the Rake 'release' task.
31
- #define CURB_VERSION "1.3.6"
32
- #define CURB_VER_NUM 1036
31
+ #define CURB_VERSION "1.3.7"
32
+ #define CURB_VER_NUM 1037
33
33
  #define CURB_VER_MAJ 1
34
34
  #define CURB_VER_MIN 3
35
- #define CURB_VER_MIC 6
35
+ #define CURB_VER_MIC 7
36
36
  #define CURB_VER_PATCH 0
37
37
 
38
38
 
data/ext/curb_easy.c CHANGED
@@ -1187,6 +1187,7 @@ static int proc_debug_handler(CURL *curl,
1187
1187
  static void curl_easy_mark(void *ptr) {
1188
1188
  ruby_curl_easy *rbce = (ruby_curl_easy *)ptr;
1189
1189
  if (rbce) {
1190
+ if (!NIL_P(rbce->self)) { rb_gc_mark(rbce->self); }
1190
1191
  if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
1191
1192
  if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
1192
1193
  if (!NIL_P(rbce->callback_error)) { rb_gc_mark(rbce->callback_error); }
@@ -5581,6 +5582,17 @@ static VALUE ruby_curl_easy_last_error(VALUE self) {
5581
5582
  * @note Some options - like url or cookie - aren't set directly throught +curl_easy_setopt+, but stored in the Ruby object state.
5582
5583
  * @note When +curl_easy_setopt+ is called, return value is not checked here.
5583
5584
  */
5585
+ static long ruby_curl_easy_option_to_long(VALUE value) {
5586
+ if (value == Qtrue) {
5587
+ return 1L;
5588
+ }
5589
+ if (value == Qfalse) {
5590
+ return 0L;
5591
+ }
5592
+
5593
+ return NUM2LONG(rb_funcall(value, rb_intern("to_i"), 0));
5594
+ }
5595
+
5584
5596
  static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
5585
5597
  ruby_curl_easy *rbce;
5586
5598
  long option = NUM2LONG(opt);
@@ -5696,59 +5708,76 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
5696
5708
  /* FTP-specific toggles */
5697
5709
  #ifdef HAVE_CURLOPT_DIRLISTONLY
5698
5710
  case CURLOPT_DIRLISTONLY: {
5699
- int type = rb_type(val);
5700
- VALUE value;
5701
- if (type == T_TRUE) {
5702
- value = rb_int_new(1);
5703
- } else if (type == T_FALSE) {
5704
- value = rb_int_new(0);
5705
- } else {
5706
- value = rb_funcall(val, rb_intern("to_i"), 0);
5707
- }
5708
- curl_easy_setopt(rbce->curl, CURLOPT_DIRLISTONLY, NUM2LONG(value));
5711
+ curl_easy_setopt(rbce->curl, CURLOPT_DIRLISTONLY, ruby_curl_easy_option_to_long(val));
5709
5712
  } break;
5710
5713
  #endif
5714
+ #ifdef HAVE_CURLOPT_FTPPORT
5715
+ case CURLOPT_FTPPORT:
5716
+ curl_easy_setopt(rbce->curl, CURLOPT_FTPPORT, NIL_P(val) ? NULL : StringValueCStr(val));
5717
+ break;
5718
+ #endif
5719
+ #ifdef HAVE_CURLOPT_APPEND
5720
+ case CURLOPT_APPEND:
5721
+ curl_easy_setopt(rbce->curl, CURLOPT_APPEND, ruby_curl_easy_option_to_long(val));
5722
+ break;
5723
+ #endif
5711
5724
  #ifdef HAVE_CURLOPT_FTP_USE_EPSV
5712
- case CURLOPT_FTP_USE_EPSV: {
5713
- int type = rb_type(val);
5714
- VALUE value;
5715
- if (type == T_TRUE) {
5716
- value = rb_int_new(1);
5717
- } else if (type == T_FALSE) {
5718
- value = rb_int_new(0);
5719
- } else {
5720
- value = rb_funcall(val, rb_intern("to_i"), 0);
5721
- }
5722
- curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPSV, NUM2LONG(value));
5723
- } break;
5725
+ case CURLOPT_FTP_USE_EPSV:
5726
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPSV, ruby_curl_easy_option_to_long(val));
5727
+ break;
5724
5728
  #endif
5725
5729
  #ifdef HAVE_CURLOPT_FTP_USE_EPRT
5726
- case CURLOPT_FTP_USE_EPRT: {
5727
- int type = rb_type(val);
5728
- VALUE value;
5729
- if (type == T_TRUE) {
5730
- value = rb_int_new(1);
5731
- } else if (type == T_FALSE) {
5732
- value = rb_int_new(0);
5733
- } else {
5734
- value = rb_funcall(val, rb_intern("to_i"), 0);
5735
- }
5736
- curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPRT, NUM2LONG(value));
5737
- } break;
5730
+ case CURLOPT_FTP_USE_EPRT:
5731
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPRT, ruby_curl_easy_option_to_long(val));
5732
+ break;
5733
+ #endif
5734
+ #ifdef HAVE_CURLOPT_FTP_USE_PRET
5735
+ case CURLOPT_FTP_USE_PRET:
5736
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_PRET, ruby_curl_easy_option_to_long(val));
5737
+ break;
5738
+ #endif
5739
+ #ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
5740
+ case CURLOPT_FTP_CREATE_MISSING_DIRS:
5741
+ rb_easy_set("ftp_create_missing_dirs", val);
5742
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_CREATE_MISSING_DIRS, ruby_curl_easy_option_to_long(val));
5743
+ break;
5744
+ #endif
5745
+ #ifdef HAVE_CURLOPT_FTP_RESPONSE_TIMEOUT
5746
+ case CURLOPT_FTP_RESPONSE_TIMEOUT:
5747
+ rbce->ftp_response_timeout = ruby_curl_easy_option_to_long(val);
5748
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
5749
+ break;
5750
+ #endif
5751
+ #ifdef HAVE_CURLOPT_FTP_ALTERNATIVE_TO_USER
5752
+ case CURLOPT_FTP_ALTERNATIVE_TO_USER:
5753
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, NIL_P(val) ? NULL : StringValueCStr(val));
5754
+ break;
5738
5755
  #endif
5739
5756
  #ifdef HAVE_CURLOPT_FTP_SKIP_PASV_IP
5740
- case CURLOPT_FTP_SKIP_PASV_IP: {
5741
- int type = rb_type(val);
5742
- VALUE value;
5743
- if (type == T_TRUE) {
5744
- value = rb_int_new(1);
5745
- } else if (type == T_FALSE) {
5746
- value = rb_int_new(0);
5747
- } else {
5748
- value = rb_funcall(val, rb_intern("to_i"), 0);
5749
- }
5750
- curl_easy_setopt(rbce->curl, CURLOPT_FTP_SKIP_PASV_IP, NUM2LONG(value));
5751
- } break;
5757
+ case CURLOPT_FTP_SKIP_PASV_IP:
5758
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_SKIP_PASV_IP, ruby_curl_easy_option_to_long(val));
5759
+ break;
5760
+ #endif
5761
+ #ifdef HAVE_CURLOPT_FTPSSLAUTH
5762
+ case CURLOPT_FTPSSLAUTH:
5763
+ curl_easy_setopt(rbce->curl, CURLOPT_FTPSSLAUTH, ruby_curl_easy_option_to_long(val));
5764
+ break;
5765
+ #endif
5766
+ #ifdef HAVE_CURLOPT_FTP_SSL_CCC
5767
+ case CURLOPT_FTP_SSL_CCC:
5768
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_SSL_CCC, ruby_curl_easy_option_to_long(val));
5769
+ break;
5770
+ #endif
5771
+ #ifdef HAVE_CURLOPT_FTP_ACCOUNT
5772
+ case CURLOPT_FTP_ACCOUNT:
5773
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_ACCOUNT, NIL_P(val) ? NULL : StringValueCStr(val));
5774
+ break;
5775
+ #endif
5776
+ #ifdef HAVE_CURLOPT_FTP_FILEMETHOD
5777
+ case CURLOPT_FTP_FILEMETHOD:
5778
+ rbce->ftp_filemethod = ruby_curl_easy_option_to_long(val);
5779
+ curl_easy_setopt(rbce->curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
5780
+ break;
5752
5781
  #endif
5753
5782
  case CURLOPT_RANGE: {
5754
5783
  curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
@@ -5955,6 +5984,34 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
5955
5984
  return val;
5956
5985
  }
5957
5986
 
5987
+ #ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
5988
+ /*
5989
+ * call-seq:
5990
+ * easy.ftp_create_missing_dirs = boolean_or_mode => boolean_or_mode
5991
+ *
5992
+ * Configure whether libcurl creates missing directories for an FTP or SFTP
5993
+ * transfer. In addition to true and false, this accepts the
5994
+ * Curl::CURLFTP_CREATE_DIR_* mode constants when provided by libcurl.
5995
+ */
5996
+ static VALUE ruby_curl_easy_ftp_create_missing_dirs_set(VALUE self, VALUE value) {
5997
+ return ruby_curl_easy_set_opt(
5998
+ self,
5999
+ LONG2NUM(CURLOPT_FTP_CREATE_MISSING_DIRS),
6000
+ value
6001
+ );
6002
+ }
6003
+
6004
+ /*
6005
+ * call-seq:
6006
+ * easy.ftp_create_missing_dirs => boolean, number, or nil
6007
+ *
6008
+ * Return the configured missing-directory creation mode.
6009
+ */
6010
+ static VALUE ruby_curl_easy_ftp_create_missing_dirs_get(VALUE self) {
6011
+ CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_create_missing_dirs);
6012
+ }
6013
+ #endif
6014
+
5958
6015
  /*
5959
6016
  * call-seq:
5960
6017
  * easy.getinfo(opt) => nil
@@ -6162,6 +6219,10 @@ void init_curb_easy() {
6162
6219
  rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
6163
6220
  rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
6164
6221
  rb_define_method(cCurlEasy, "ftp_response_timeout", ruby_curl_easy_ftp_response_timeout_get, 0);
6222
+ #ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
6223
+ rb_define_method(cCurlEasy, "ftp_create_missing_dirs=", ruby_curl_easy_ftp_create_missing_dirs_set, 1);
6224
+ rb_define_method(cCurlEasy, "ftp_create_missing_dirs", ruby_curl_easy_ftp_create_missing_dirs_get, 0);
6225
+ #endif
6165
6226
  rb_define_method(cCurlEasy, "low_speed_limit=", ruby_curl_easy_low_speed_limit_set, 1);
6166
6227
  rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
6167
6228
  rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);