curb 1.3.7 → 1.4.1

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.
@@ -0,0 +1,141 @@
1
+ require File.expand_path('helper', __dir__)
2
+
3
+ class TestCurbRactor < Test::Unit::TestCase
4
+ include TestServerMethods
5
+
6
+ RACTOR_WORKERS = 4
7
+ REQUESTS_PER_WORKER = 3
8
+
9
+ def setup
10
+ super
11
+ server_setup
12
+ end
13
+
14
+ def test_exported_string_constants_are_shareable
15
+ omit('Ractor is unavailable on this Ruby') unless defined?(Ractor)
16
+
17
+ %i[CURB_VERSION VERSION CURL_VERSION LONG_VERSION CURL_LONG_VERSION].each do |name|
18
+ value = Curl.const_get(name)
19
+ assert_predicate value, :frozen?, "Curl::#{name} should be frozen"
20
+ assert Ractor.shareable?(value), "Curl::#{name} should be Ractor-shareable"
21
+ end
22
+ end
23
+
24
+ def test_independent_ractors_can_perform_requests_concurrently
25
+ original_timeout = Curl::Multi.default_timeout
26
+ original_autoclose = Curl::Multi.autoclose
27
+ omit_unless_curb_ractor_safe
28
+
29
+ url = TestServlet.url
30
+
31
+ workers = RACTOR_WORKERS.times.map do |worker_id|
32
+ Ractor.new(url, worker_id, REQUESTS_PER_WORKER) do |target, id, request_count|
33
+ Curl.safe! do |config|
34
+ config.protocols = [:http]
35
+ config.network_policy = :none # This concurrency fixture uses localhost.
36
+ end
37
+ Curl::Multi.default_timeout = 25 + id
38
+ Curl::Multi.autoclose = true
39
+
40
+ responses = request_count.times.map do
41
+ chunks = 0
42
+ easy = Curl::Easy.new(target)
43
+ easy.on_body do |data|
44
+ chunks += 1
45
+ data.bytesize
46
+ end
47
+ easy.perform
48
+ [easy.response_code, chunks]
49
+ end
50
+
51
+ {
52
+ responses: responses,
53
+ timeout: Curl::Multi.default_timeout,
54
+ autoclose: Curl::Multi.autoclose,
55
+ deferred_closes: Curl::Easy.deferred_multi_closes.length,
56
+ version: Curl::VERSION,
57
+ }
58
+ end
59
+ end
60
+
61
+ results = workers.map { |worker| ractor_value(worker) }
62
+
63
+ results.each_with_index do |result, worker_id|
64
+ assert_equal REQUESTS_PER_WORKER, result[:responses].length
65
+ result[:responses].each do |status, chunks|
66
+ assert_equal 200, status
67
+ assert_operator chunks, :>=, 1
68
+ end
69
+ assert_equal 25 + worker_id, result[:timeout]
70
+ assert_equal true, result[:autoclose]
71
+ assert_equal 0, result[:deferred_closes]
72
+ assert_equal Curl::VERSION, result[:version]
73
+ end
74
+
75
+ assert_equal original_timeout, Curl::Multi.default_timeout
76
+ assert_equal original_autoclose, Curl::Multi.autoclose
77
+ ensure
78
+ Curl::Multi.default_timeout = original_timeout if defined?(original_timeout)
79
+ Curl::Multi.autoclose = original_autoclose if defined?(original_autoclose)
80
+ end
81
+
82
+ def test_multipart_snapshots_are_private_to_parallel_ractors
83
+ omit_unless_curb_ractor_safe
84
+ worker_count = Integer(ENV.fetch('CURB_MULTIPART_RACTORS', '4'))
85
+ request_count = Integer(ENV.fetch('CURB_MULTIPART_REQUESTS', '5'))
86
+ workers = worker_count.times.map do |worker_id|
87
+ Ractor.new(TestServlet.url, worker_id, request_count) do |url, id, count|
88
+ easy = Curl::Easy.new(url)
89
+ easy.multipart_form_post = true
90
+ count.times do |iteration|
91
+ name = +"field_#{id}_#{iteration}"
92
+ payload = "payload_#{id}_#{iteration}\0" + ('x' * 1024)
93
+ expected_name = name.dup
94
+ expected_payload = payload.dup
95
+ direct = Curl::PostField.content(name, payload, 'application/octet-stream')
96
+ file = Curl::PostField.file('upload', 'payload.bin') { payload }
97
+ later = Curl::PostField.content('later') do
98
+ name.replace('changed' * 1000)
99
+ payload.replace('changed' * 1000)
100
+ # Ruby #21537: explicit GC in a Windows Ractor can deadlock
101
+ # the VM barrier. Keep parallel mutation coverage on Windows;
102
+ # single-Ractor compaction is covered by the PostField tests.
103
+ if iteration % 10 == 0 && !WINDOWS
104
+ GC.start
105
+ GC.compact if GC.respond_to?(:compact)
106
+ end
107
+ 'done'
108
+ end
109
+ easy.http_post(direct, file, later)
110
+ body = easy.body_str
111
+ unless easy.response_code == 200 &&
112
+ body.include?("name=\"#{expected_name}\"") &&
113
+ body.include?('filename="payload.bin"') &&
114
+ body.scan(expected_payload).length == 2 &&
115
+ !body.include?('changed')
116
+ raise "Multipart snapshot changed in Ractor #{id}, request #{iteration}"
117
+ end
118
+ end
119
+ easy.close
120
+ count
121
+ end
122
+ end
123
+ assert_equal Array.new(worker_count, request_count), workers.map { |worker| ractor_value(worker) }
124
+ end
125
+
126
+ private
127
+
128
+ def omit_unless_curb_ractor_safe
129
+ omit('Ractor is unavailable on this Ruby') unless defined?(Ractor)
130
+ omit('This build does not advertise Ractor-safe native support') unless
131
+ Curl.const_defined?(:RACTOR_SAFE) && Curl::RACTOR_SAFE
132
+ end
133
+
134
+ def ractor_value(ractor)
135
+ if ractor.respond_to?(:value)
136
+ ractor.value
137
+ else
138
+ ractor.take
139
+ end
140
+ end
141
+ 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.3.7
4
+ version: 1.4.1
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: 2026-07-10 00:00:00.000000000 Z
11
+ date: 2026-10-21 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
@@ -21,6 +21,7 @@ extra_rdoc_files:
21
21
  - LICENSE
22
22
  - README.md
23
23
  files:
24
+ - ChangeLog.md
24
25
  - LICENSE
25
26
  - README.md
26
27
  - Rakefile
@@ -78,13 +79,17 @@ files:
78
79
  - tests/tc_curl_easy_setopt.rb
79
80
  - tests/tc_curl_maxfilesize.rb
80
81
  - tests/tc_curl_multi.rb
82
+ - tests/tc_curl_multi_poll.rb
83
+ - tests/tc_curl_multi_socket_poller.rb
81
84
  - tests/tc_curl_native_coverage.rb
82
85
  - tests/tc_curl_network_policy.rb
83
86
  - tests/tc_curl_postfield.rb
84
87
  - tests/tc_curl_protocols.rb
88
+ - tests/tc_curl_transfer_guard.rb
85
89
  - tests/tc_fiber_scheduler.rb
86
90
  - tests/tc_ftp_options.rb
87
91
  - tests/tc_gc_compact.rb
92
+ - tests/tc_ractor.rb
88
93
  - tests/tc_test_server_methods.rb
89
94
  - tests/timeout.rb
90
95
  - tests/timeout_server.rb
@@ -148,13 +153,17 @@ test_files:
148
153
  - tests/tc_curl_easy_setopt.rb
149
154
  - tests/tc_curl_maxfilesize.rb
150
155
  - tests/tc_curl_multi.rb
156
+ - tests/tc_curl_multi_poll.rb
157
+ - tests/tc_curl_multi_socket_poller.rb
151
158
  - tests/tc_curl_native_coverage.rb
152
159
  - tests/tc_curl_network_policy.rb
153
160
  - tests/tc_curl_postfield.rb
154
161
  - tests/tc_curl_protocols.rb
162
+ - tests/tc_curl_transfer_guard.rb
155
163
  - tests/tc_fiber_scheduler.rb
156
164
  - tests/tc_ftp_options.rb
157
165
  - tests/tc_gc_compact.rb
166
+ - tests/tc_ractor.rb
158
167
  - tests/tc_test_server_methods.rb
159
168
  - tests/timeout.rb
160
169
  - tests/timeout_server.rb