curb 1.0.7 → 1.0.9

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: 805549f6e3fe9190d76c507fa67bf6f6e2a6bbe65bde611cb3aeee6c78cad51f
4
- data.tar.gz: 7f6cab9c618e4535e7ff46b48d11bb5f307158d850b95bd560432dfeb9ea3144
3
+ metadata.gz: 0105bb19d8f3c70c7b16dc47ede5eef29b26d78a765b6ab9ac19c81dc34c647a
4
+ data.tar.gz: 8bb7441583b1caa916969f4a7aad3785777de7912347f6c454bb110c4ab50b08
5
5
  SHA512:
6
- metadata.gz: 98f411070f4c3ef1646de29052a2c9a37e7aa2c9009102a7f4e483d1d1188d8bbdae50647e6dd4c8c7439120619e22df5f8c90bba6e1a088e2762cc29109c63d
7
- data.tar.gz: bb8ad84d03972d1e42ce61622060019edc4d6286bab9ab459d2fe9e8ccd3cdc04490a8ba58715fd4efa30e3babf82ac96afce3f5b80fddd1d0bd4d47b197a5f1
6
+ metadata.gz: b9d63ab6203a5d37fe3ef02b081f92afa9ece68acdde249d6f3e09fd21fec5fd1342fa6e2fcbfb6fc58a6fd5ad2fce44fd0915d0b0bd31902cc9c5aef976d250
7
+ data.tar.gz: cb9f110ebeddb88eddc31d9cf1985148365c6abe5a378e2ea157414dd7bc96c59b2b2883ba0b21ac1569d82ee4bc8744cfbeaae1eaae07245c81a146bae78510
data/README.markdown CHANGED
@@ -37,6 +37,103 @@ POST request
37
37
  puts res.body
38
38
  ```
39
39
 
40
+ ## FTP Support
41
+
42
+ require 'curb'
43
+
44
+ ### Basic FTP Download
45
+ ```ruby
46
+ puts "=== FTP Download Example ==="
47
+ ftp = Curl::Easy.new('ftp://ftp.example.com/remote/file.txt')
48
+ ftp.username = 'user'
49
+ ftp.password = 'password'
50
+ ftp.perform
51
+ puts ftp.body
52
+ ```
53
+
54
+ ### FTP Upload
55
+ ```ruby
56
+ puts "\n=== FTP Upload Example ==="
57
+ upload = Curl::Easy.new('ftp://ftp.example.com/remote/upload.txt')
58
+ upload.username = 'user'
59
+ upload.password = 'password'
60
+ upload.upload = true
61
+ upload.put_data = File.read('local_file.txt')
62
+ upload.perform
63
+ ```
64
+
65
+ ### List Directory Contents
66
+ ```ruby
67
+ puts "\n=== FTP Directory Listing Example ==="
68
+ list = Curl::Easy.new('ftp://ftp.example.com/remote/directory/')
69
+ list.username = 'user'
70
+ list.password = 'password'
71
+ list.dirlistonly = true
72
+ list.perform
73
+ puts list.body
74
+ ```
75
+
76
+ ### Advanced FTP Usage with Various Options
77
+ ```
78
+ puts "\n=== Advanced FTP Example ==="
79
+ advanced = Curl::Easy.new do |curl|
80
+ curl.url = 'ftp://ftp.example.com/remote/file.txt'
81
+ curl.username = 'user'
82
+ curl.password = 'password'
83
+
84
+ # FTP Options
85
+ curl.ftp_response_timeout = 30
86
+ curl.ftp_create_missing_dirs = true # Create directories if they don't exist
87
+ curl.ftp_filemethod = Curl::CURL_MULTICWD # Use multicwd method for traversing paths
88
+
89
+ # SSL/TLS Options for FTPS
90
+ curl.use_ssl = Curl::CURLUSESSL_ALL # Use SSL/TLS for control and data
91
+ curl.ssl_verify_peer = true
92
+ curl.ssl_verify_host = true
93
+ curl.cacert = "/path/to/cacert.pem"
94
+
95
+ # Progress callback
96
+ curl.on_progress do |dl_total, dl_now, ul_total, ul_now|
97
+ puts "Download: #{dl_now}/#{dl_total} Upload: #{ul_now}/#{ul_total}"
98
+ true # must return true to continue
99
+ end
100
+
101
+ # Debug output
102
+ curl.verbose = true
103
+ curl.on_debug do |type, data|
104
+ puts "#{type}: #{data}"
105
+ true
106
+ end
107
+ end
108
+
109
+ advanced.perform
110
+ ```
111
+
112
+ ### Parallel FTP Downloads
113
+ ```
114
+ puts "\n=== Parallel FTP Downloads Example ==="
115
+ urls = [
116
+ 'ftp://ftp.example.com/file1.txt',
117
+ 'ftp://ftp.example.com/file2.txt',
118
+ 'ftp://ftp.example.com/file3.txt'
119
+ ]
120
+ ```
121
+
122
+ ### Common options for all connections
123
+ ```
124
+ options = {
125
+ :username => 'user',
126
+ :password => 'password',
127
+ :timeout => 30,
128
+ :on_success => proc { |easy| puts "Successfully downloaded: #{easy.url}" },
129
+ :on_failure => proc { |easy, code| puts "Failed to download: #{easy.url} (#{code})" }
130
+ }
131
+
132
+ Curl::Multi.download(urls, options) do |curl, file_path|
133
+ puts "Completed downloading to: #{file_path}"
134
+ end
135
+ ```
136
+
40
137
  ## You will need
41
138
 
42
139
  * 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...)
@@ -50,20 +147,23 @@ A **non-exhaustive** set of compatibility versions of the libcurl library
50
147
  with this gem are as follows. (Note that these are only the ones that have been
51
148
  tested and reported to work across a variety of platforms / rubies)
52
149
 
53
- | Gem Version | Release Date | libcurl versions |
54
- | ----------- | ----------- | ---------------- |
55
- | 1.0.5 | Jan 2023 | 7.58 - 7.87 |
56
- | 1.0.4 | Jan 2023 | 7.58 - 7.87 |
57
- | 1.0.3* | Dec 2022 | 7.58 - 7.87 |
58
- | 1.0.2* | Dec 2022 | 7.58 - 7.87 |
59
- | 1.0.1 | Apr 2022 | 7.58 - 7.87 |
60
- | 1.0.0 | Jan 2022 | 7.58 - 7.87 |
61
- | 0.9.8 | Jan 2019 | 7.58 - 7.81 |
62
- | 0.9.7 | Nov 2018 | 7.56 - 7.60 |
63
- | 0.9.6 | May 2018 | 7.51 - 7.59 |
64
- | 0.9.5 | May 2018 | 7.51 - 7.59 |
65
- | 0.9.4 | Aug 2017 | 7.41 - 7.58 |
66
- | 0.9.3 | Apr 2016 | 7.26 - 7.58 |
150
+ | Gem Version | Release Date | libcurl versions |
151
+ | ----------- | -------------- | ----------------- |
152
+ | 1.0.8 | Feb 10, 2025 | 7.58 8.12.1 |
153
+ | 1.0.7 | Feb 09, 2025 | 7.58 8.12.1 |
154
+ | 1.0.6 | Aug 23, 2024 | 7.58 8.12.1 |
155
+ | 1.0.5 | Jan 2023 | 7.58 8.12.1 |
156
+ | 1.0.4 | Jan 2023 | 7.58 8.12.1 |
157
+ | 1.0.3* | Dec 2022 | 7.58 8.12.1 |
158
+ | 1.0.2* | Dec 2022 | 7.58 8.12.1 |
159
+ | 1.0.1 | Apr 2022 | 7.58 8.12.1 |
160
+ | 1.0.0 | Jan 2022 | 7.58 8.12.1 |
161
+ | 0.9.8 | Jan 2019 | 7.58 7.81 |
162
+ | 0.9.7 | Nov 2018 | 7.56 7.60 |
163
+ | 0.9.6 | May 2018 | 7.51 7.59 |
164
+ | 0.9.5 | May 2018 | 7.51 – 7.59 |
165
+ | 0.9.4 | Aug 2017 | 7.41 – 7.58 |
166
+ | 0.9.3 | Apr 2016 | 7.26 – 7.58 |
67
167
 
68
168
  ```*avoid using these version are known to have issues with segmentation faults```
69
169
 
@@ -215,7 +315,7 @@ c = Curl::Easy.new
215
315
  ["http://www.google.co.uk", "http://www.ruby-lang.org/"].map do |url|
216
316
  c.url = url
217
317
  c.perform
218
- c.body_str
318
+ c.body
219
319
  end
220
320
  ```
221
321
 
@@ -242,7 +342,7 @@ c = Curl::Easy.new("https://http2.akamai.com")
242
342
  c.set(:HTTP_VERSION, Curl::HTTP_2_0)
243
343
 
244
344
  c.perform
245
- puts (c.body_str.include? "You are using HTTP/2 right now!") ? "HTTP/2" : "HTTP/1.x"
345
+ puts (c.body.include? "You are using HTTP/2 right now!") ? "HTTP/2" : "HTTP/1.x"
246
346
  ```
247
347
 
248
348
  ### Multi Interface (Basic HTTP GET):
data/Rakefile CHANGED
@@ -3,6 +3,10 @@
3
3
  require 'rake/clean'
4
4
  require 'rake/testtask'
5
5
  require "ruby_memcheck"
6
+ begin
7
+ require 'mixlib/shellout'
8
+ rescue LoadError
9
+ end
6
10
 
7
11
  CLEAN.include '**/*.o'
8
12
  CLEAN.include "**/*.#{(defined?(RbConfig) ? RbConfig : Config)::MAKEFILE_CONFIG['DLEXT']}"
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.0.7"
32
- #define CURB_VER_NUM 1007
31
+ #define CURB_VERSION "1.0.9"
32
+ #define CURB_VER_NUM 1009
33
33
  #define CURB_VER_MAJ 1
34
34
  #define CURB_VER_MIN 0
35
- #define CURB_VER_MIC 7
35
+ #define CURB_VER_MIC 9
36
36
  #define CURB_VER_PATCH 0
37
37
 
38
38
 
data/ext/curb_easy.c CHANGED
@@ -2535,7 +2535,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2535
2535
  rb_iterate(rb_each, rb_easy_get("proxy_headers"), cb_each_http_proxy_header, wrap);
2536
2536
  } else {
2537
2537
  VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
2538
- *phdrs = curl_slist_append(*hdrs, StringValuePtr(proxy_headers_str));
2538
+ *phdrs = curl_slist_append(*phdrs, StringValuePtr(proxy_headers_str));
2539
2539
  }
2540
2540
 
2541
2541
  if (*phdrs) {
@@ -2758,6 +2758,88 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2758
2758
  }
2759
2759
  }
2760
2760
 
2761
+ /*
2762
+ * call-seq:
2763
+ * easy.http_patch("url=encoded%20form%20data;and=so%20on") => true
2764
+ * easy.http_patch("url=encoded%20form%20data", "and=so%20on", ...) => true
2765
+ * easy.http_patch("url=encoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
2766
+ * easy.http_patch(Curl::PostField, Curl::PostField ..., Curl::PostField) => true
2767
+ *
2768
+ * PATCH the specified formdata to the currently configured URL using
2769
+ * the current options set for this Curl::Easy instance. This method
2770
+ * always returns true, or raises an exception (defined under
2771
+ * Curl::Err) on error.
2772
+ *
2773
+ * When multipart_form_post is true the multipart logic is used; otherwise,
2774
+ * the arguments are joined into a raw PATCH body.
2775
+ */
2776
+ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
2777
+ ruby_curl_easy *rbce;
2778
+ CURL *curl;
2779
+ int i;
2780
+ VALUE args_ary;
2781
+
2782
+ rb_scan_args(argc, argv, "*", &args_ary);
2783
+ Data_Get_Struct(self, ruby_curl_easy, rbce);
2784
+ curl = rbce->curl;
2785
+
2786
+ /* Clear the error buffer */
2787
+ memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
2788
+
2789
+ /* Set the custom HTTP method to PATCH */
2790
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
2791
+
2792
+ if (rbce->multipart_form_post) {
2793
+ VALUE ret;
2794
+ struct curl_httppost *first = NULL, *last = NULL;
2795
+
2796
+ /* Build the multipart form (same logic as for POST) */
2797
+ for (i = 0; i < argc; i++) {
2798
+ if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
2799
+ append_to_form(argv[i], &first, &last);
2800
+ } else if (rb_type(argv[i]) == T_ARRAY) {
2801
+ long j, argv_len = RARRAY_LEN(argv[i]);
2802
+ for (j = 0; j < argv_len; ++j) {
2803
+ if (rb_obj_is_instance_of(rb_ary_entry(argv[i], j), cCurlPostField)) {
2804
+ append_to_form(rb_ary_entry(argv[i], j), &first, &last);
2805
+ } else {
2806
+ rb_raise(eCurlErrInvalidPostField,
2807
+ "You must use PostFields only with multipart form posts");
2808
+ return Qnil;
2809
+ }
2810
+ }
2811
+ } else {
2812
+ rb_raise(eCurlErrInvalidPostField,
2813
+ "You must use PostFields only with multipart form posts");
2814
+ return Qnil;
2815
+ }
2816
+ }
2817
+ /* Disable the POST flag */
2818
+ curl_easy_setopt(curl, CURLOPT_POST, 0);
2819
+ /* Use the built multipart form as the request body */
2820
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
2821
+ ret = rb_funcall(self, rb_intern("perform"), 0);
2822
+ curl_formfree(first);
2823
+ return ret;
2824
+ } else {
2825
+ /* Join arguments into a raw PATCH body */
2826
+ VALUE patch_body = rb_funcall(args_ary, idJoin, 1, rbstrAmp);
2827
+ if (patch_body == Qnil) {
2828
+ rb_raise(eCurlErrError, "Failed to join arguments");
2829
+ return Qnil;
2830
+ } else {
2831
+ if (rb_type(patch_body) == T_STRING && RSTRING_LEN(patch_body) > 0) {
2832
+ ruby_curl_easy_post_body_set(self, patch_body);
2833
+ }
2834
+ /* If postdata_buffer is still nil, set it so that the PATCH header is enabled */
2835
+ if (rb_easy_nil("postdata_buffer")) {
2836
+ ruby_curl_easy_post_body_set(self, patch_body);
2837
+ }
2838
+ return rb_funcall(self, rb_intern("perform"), 0);
2839
+ }
2840
+ }
2841
+ }
2842
+
2761
2843
  /*
2762
2844
  * call-seq:
2763
2845
  * easy.http_put(data) => true
@@ -2766,18 +2848,70 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
2766
2848
  * current options set for this Curl::Easy instance. This method always
2767
2849
  * returns true, or raises an exception (defined under Curl::Err) on error.
2768
2850
  */
2769
- static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
2851
+ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
2770
2852
  ruby_curl_easy *rbce;
2771
2853
  CURL *curl;
2854
+ VALUE args_ary;
2855
+ int i;
2772
2856
 
2857
+ rb_scan_args(argc, argv, "*", &args_ary);
2773
2858
  Data_Get_Struct(self, ruby_curl_easy, rbce);
2774
2859
  curl = rbce->curl;
2775
2860
 
2776
2861
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
2862
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
2777
2863
 
2778
- curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2779
- ruby_curl_easy_put_data_set(self, data);
2780
-
2864
+ /* New: if no arguments were provided, treat as an empty PUT */
2865
+ if (RARRAY_LEN(args_ary) == 0) {
2866
+ /* Option 1: explicitly set an empty body */
2867
+ ruby_curl_easy_put_data_set(self, rb_str_new2(""));
2868
+ }
2869
+ /* If a single argument is given and it is a String or responds to read, use legacy behavior */
2870
+ else if (RARRAY_LEN(args_ary) == 1 &&
2871
+ (rb_type(rb_ary_entry(args_ary, 0)) == T_STRING ||
2872
+ rb_respond_to(rb_ary_entry(args_ary, 0), rb_intern("read")))) {
2873
+ ruby_curl_easy_put_data_set(self, rb_ary_entry(args_ary, 0));
2874
+ }
2875
+ /* Otherwise, if multipart_form_post is true, use multipart logic */
2876
+ else if (rbce->multipart_form_post) {
2877
+ VALUE ret;
2878
+ struct curl_httppost *first = NULL, *last = NULL;
2879
+ for (i = 0; i < RARRAY_LEN(args_ary); i++) {
2880
+ VALUE field = rb_ary_entry(args_ary, i);
2881
+ if (rb_obj_is_instance_of(field, cCurlPostField)) {
2882
+ append_to_form(field, &first, &last);
2883
+ } else if (rb_type(field) == T_ARRAY) {
2884
+ long j;
2885
+ for (j = 0; j < RARRAY_LEN(field); j++) {
2886
+ VALUE subfield = rb_ary_entry(field, j);
2887
+ if (rb_obj_is_instance_of(subfield, cCurlPostField)) {
2888
+ append_to_form(subfield, &first, &last);
2889
+ } else {
2890
+ rb_raise(eCurlErrInvalidPostField,
2891
+ "You must use PostFields only with multipart form posts");
2892
+ }
2893
+ }
2894
+ } else {
2895
+ rb_raise(eCurlErrInvalidPostField,
2896
+ "You must use PostFields only with multipart form posts");
2897
+ }
2898
+ }
2899
+ curl_easy_setopt(curl, CURLOPT_POST, 0);
2900
+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
2901
+ /* Set the method explicitly to PUT */
2902
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
2903
+ ret = rb_funcall(self, rb_intern("perform"), 0);
2904
+ curl_formfree(first);
2905
+ return ret;
2906
+ }
2907
+ /* Fallback: join all arguments */
2908
+ else {
2909
+ VALUE post_body = rb_funcall(args_ary, idJoin, 1, rbstrAmp);
2910
+ if (post_body != Qnil && rb_type(post_body) == T_STRING &&
2911
+ RSTRING_LEN(post_body) > 0) {
2912
+ ruby_curl_easy_put_data_set(self, post_body);
2913
+ }
2914
+ }
2781
2915
  return rb_funcall(self, rb_intern("perform"), 0);
2782
2916
  }
2783
2917
 
@@ -3946,7 +4080,8 @@ void init_curb_easy() {
3946
4080
 
3947
4081
  rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
3948
4082
  rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
3949
- rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
4083
+ rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, -1);
4084
+ rb_define_method(cCurlEasy, "http_patch", ruby_curl_easy_perform_patch, -1);
3950
4085
 
3951
4086
  /* Post-perform info methods */
3952
4087
  rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
data/lib/curl/easy.rb CHANGED
@@ -374,13 +374,36 @@ module Curl
374
374
  #
375
375
  # call-seq:
376
376
  # Curl::Easy.http_put(url, data) {|c| ... }
377
+ # Curl::Easy.http_put(url, "some=urlencoded%20form%20data&and=so%20on") => true
378
+ # Curl::Easy.http_put(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
379
+ # Curl::Easy.http_put(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
380
+ # Curl::Easy.http_put(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
377
381
  #
378
382
  # see easy.http_put
379
383
  #
380
- def http_put(url, data)
381
- c = Curl::Easy.new url
384
+ def http_put(*args)
385
+ url = args.shift
386
+ c = Curl::Easy.new(url)
387
+ yield c if block_given?
388
+ c.http_put(*args)
389
+ c
390
+ end
391
+
392
+ #
393
+ # call-seq:
394
+ # Curl::Easy.http_patch(url, data) {|c| ... }
395
+ # Curl::Easy.http_patch(url, "some=urlencoded%20form%20data&and=so%20on") => true
396
+ # Curl::Easy.http_patch(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
397
+ # Curl::Easy.http_patch(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
398
+ # Curl::Easy.http_patch(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
399
+ #
400
+ # see easy.http_patch
401
+ #
402
+ def http_patch(*args)
403
+ url = args.shift
404
+ c = Curl::Easy.new(url)
382
405
  yield c if block_given?
383
- c.http_put data
406
+ c.http_patch(*args)
384
407
  c
385
408
  end
386
409
 
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+
4
+ require 'curb'
5
+
6
+ class BugIssue102 < Test::Unit::TestCase
7
+
8
+ def test_gc_closewait
9
+ 100.times do
10
+ responses = {}
11
+ requests = ["http://www.google.co.uk/", "http://www.ruby-lang.org/"]
12
+ m = Curl::Multi.new
13
+ # add a few easy handles
14
+ requests.each do |url|
15
+ responses[url] = ""
16
+ c = Curl::Easy.new(url) do|curl|
17
+ curl.follow_location = true
18
+ curl.on_body{|data| responses[url] << data; data.size }
19
+ curl.on_success {|easy| #puts "success, add more easy handles"
20
+ }
21
+ end
22
+ m.add(c)
23
+ end
24
+
25
+ m.perform do
26
+ #puts "idling... can do some work here"
27
+ end
28
+ GC.start
29
+ end
30
+ end
31
+
32
+ end
@@ -765,20 +765,27 @@ class TestCurbCurlEasy < Test::Unit::TestCase
765
765
  assert_equal 'GET', curl.body_str
766
766
  end
767
767
 
768
- def test_post_remote
768
+ def test_remote
769
769
  curl = Curl::Easy.new(TestServlet.url)
770
770
  curl.http_post([Curl::PostField.content('document_id', 5)])
771
771
  assert_equal "POST\ndocument_id=5", curl.unescape(curl.body_str)
772
+
773
+ curl.http_put([Curl::PostField.content('document_id', 5)])
774
+ assert_equal "PUT\ndocument_id=5", curl.unescape(curl.body_str)
775
+
776
+ curl.http_patch([Curl::PostField.content('document_id', 5)])
777
+ assert_equal "PATCH\ndocument_id=5", curl.unescape(curl.body_str)
772
778
  end
773
779
 
774
- def test_post_remote_is_easy_handle
780
+ def test_remote_is_easy_handle
775
781
  # see: http://pastie.org/560852 and
776
782
  # http://groups.google.com/group/curb---ruby-libcurl-bindings/browse_thread/thread/216bb2d9b037f347?hl=en
777
- [:post, :get, :head, :delete].each do |method|
783
+ [:post, :patch, :put, :get, :head, :delete].each do |method|
778
784
  retries = 0
779
785
  begin
780
786
  count = 0
781
- Curl::Easy.send("http_#{method}", TestServlet.url) do|c|
787
+ m = "http_#{method}".to_sym
788
+ Curl::Easy.send(m, TestServlet.url) do|c|
782
789
  count += 1
783
790
  assert_equal Curl::Easy, c.class
784
791
  end
@@ -787,12 +794,14 @@ class TestCurbCurlEasy < Test::Unit::TestCase
787
794
  retries+=1
788
795
  retry if retries < 3
789
796
  raise e
797
+ rescue ArgumentError => e
798
+ assert false, "#{m} - #{e.message}"
790
799
  end
791
800
  end
792
801
  end
793
802
 
794
803
  # see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
795
- def test_post_multipart_array_remote
804
+ def test_multipart_array_remote
796
805
  curl = Curl::Easy.new(TestServlet.url)
797
806
  curl.multipart_form_post = true
798
807
  fields = [
@@ -802,9 +811,23 @@ class TestCurbCurlEasy < Test::Unit::TestCase
802
811
  curl.http_post(fields)
803
812
  assert_match(/HTTP POST file upload/, curl.body_str)
804
813
  assert_match(/Content-Disposition: form-data/, curl.body_str)
814
+
815
+ curl = Curl::Easy.new(TestServlet.url)
816
+ curl.multipart_form_post = true
817
+ fields = [
818
+ Curl::PostField.file('foo', File.expand_path(File.join(File.dirname(__FILE__),'..','README.markdown'))),
819
+ Curl::PostField.file('bar', File.expand_path(File.join(File.dirname(__FILE__),'..','README.markdown')))
820
+ ]
821
+ curl.http_put(fields)
822
+ assert_match(/HTTP POST file upload/, curl.body_str)
823
+ assert_match(/Content-Disposition: form-data/, curl.body_str)
824
+
825
+ curl.http_patch(fields)
826
+ assert_match(/HTTP POST file upload/, curl.body_str)
827
+ assert_match(/Content-Disposition: form-data/, curl.body_str)
805
828
  end
806
829
 
807
- def test_post_with_body_remote
830
+ def test_with_body_remote
808
831
  curl = Curl::Easy.new(TestServlet.url)
809
832
  curl.post_body = 'foo=bar&encoded%20string=val'
810
833
 
@@ -812,23 +835,42 @@ class TestCurbCurlEasy < Test::Unit::TestCase
812
835
 
813
836
  assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
814
837
  assert_equal 'foo=bar&encoded%20string=val', curl.post_body
838
+
839
+ curl = Curl::Easy.new(TestServlet.url)
840
+ curl.put_data = 'foo=bar&encoded%20string=val'
841
+
842
+ curl.perform
843
+
844
+ assert_equal "PUT\nfoo=bar&encoded%20string=val", curl.body_str
815
845
  end
816
846
 
817
- def test_form_post_body_remote
847
+ def test_form_body_remote
818
848
  curl = Curl::Easy.new(TestServlet.url)
819
849
  curl.http_post('foo=bar', 'encoded%20string=val')
820
850
 
821
851
  assert_equal "POST\nfoo=bar&encoded%20string=val", curl.body_str
822
852
  assert_equal 'foo=bar&encoded%20string=val', curl.post_body
823
- end
824
853
 
825
- def test_post_multipart_file_remote
826
854
  curl = Curl::Easy.new(TestServlet.url)
827
- curl.multipart_form_post = true
828
- pf = Curl::PostField.file('readme', File.expand_path(File.join(File.dirname(__FILE__),'..','README.markdown')))
829
- curl.http_post(pf)
830
- assert_match(/HTTP POST file upload/, curl.body_str)
831
- assert_match(/Content-Disposition: form-data/, curl.body_str)
855
+ curl.http_put('foo=bar', 'encoded%20string=val')
856
+
857
+ assert_equal "PUT\nfoo=bar&encoded%20string=val", curl.body_str
858
+
859
+ curl = Curl::Easy.new(TestServlet.url)
860
+ curl.http_patch('foo=bar', 'encoded%20string=val')
861
+
862
+ assert_equal "PATCH\nfoo=bar&encoded%20string=val", curl.body_str
863
+ end
864
+
865
+ def test_multipart_file_remote
866
+ [:put, :post, :patch].each {|method|
867
+ curl = Curl::Easy.new(TestServlet.url)
868
+ curl.multipart_form_post = true
869
+ pf = Curl::PostField.file('readme', File.expand_path(File.join(File.dirname(__FILE__),'..','README.markdown')))
870
+ curl.send("http_#{method}", pf)
871
+ assert_match(/HTTP POST file upload/, curl.body_str)
872
+ assert_match(/Content-Disposition: form-data/, curl.body_str)
873
+ }
832
874
  end
833
875
 
834
876
  def test_delete_remote
@@ -1065,6 +1107,12 @@ class TestCurbCurlEasy < Test::Unit::TestCase
1065
1107
  assert_equal "PUT\nhello", curl.body_str
1066
1108
  curl.http('COPY')
1067
1109
  assert_equal 'COPY', curl.body_str
1110
+
1111
+ curl.http_patch
1112
+ assert_equal "PATCH\n", curl.body_str
1113
+
1114
+ curl.http_put
1115
+ assert_equal "PUT\n", curl.body_str
1068
1116
  end
1069
1117
 
1070
1118
  def test_easy_http_verbs_must_respond_to_str
@@ -58,12 +58,13 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
58
58
 
59
59
  def test_new_file_01
60
60
  pf = Curl::PostField.file('foo', 'localname')
61
+ pf.content_type = 'text/super'
61
62
 
62
63
  assert_equal 'foo', pf.name
63
64
  assert_equal 'localname', pf.local_file
64
65
  assert_equal 'localname', pf.remote_file
65
66
  assert_nothing_raised { pf.to_s }
66
- assert_nil pf.content_type
67
+ assert_equal 'text/super', pf.content_type
67
68
  assert_nil pf.content
68
69
  assert_nil pf.set_content_proc
69
70
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ross Bamford
8
8
  - Todd A. Fisher
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-09 00:00:00.000000000 Z
11
+ date: 2025-02-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings
14
14
  for the libcurl(3), a fully-featured client-side URL transfer library. cURL and
@@ -52,6 +52,7 @@ files:
52
52
  - tests/bug_follow_redirect_288.rb
53
53
  - tests/bug_instance_post_differs_from_class_post.rb
54
54
  - tests/bug_issue102.rb
55
+ - tests/bug_issue277.rb
55
56
  - tests/bug_multi_segfault.rb
56
57
  - tests/bug_postfields_crash.rb
57
58
  - tests/bug_postfields_crash2.rb
@@ -78,7 +79,8 @@ files:
78
79
  homepage: https://github.com/taf2/curb
79
80
  licenses:
80
81
  - Ruby
81
- metadata: {}
82
+ metadata:
83
+ changelog_uri: https://github.com/taf2/curb/blob/master/ChangeLog.md
82
84
  rdoc_options:
83
85
  - "--main"
84
86
  - README.markdown
@@ -108,6 +110,7 @@ test_files:
108
110
  - tests/bug_follow_redirect_288.rb
109
111
  - tests/bug_instance_post_differs_from_class_post.rb
110
112
  - tests/bug_issue102.rb
113
+ - tests/bug_issue277.rb
111
114
  - tests/bug_multi_segfault.rb
112
115
  - tests/bug_postfields_crash.rb
113
116
  - tests/bug_postfields_crash2.rb