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.
- checksums.yaml +4 -4
- data/ChangeLog.md +432 -0
- data/README.md +62 -5
- data/Rakefile +12 -1
- data/ext/curb.c +17 -4
- data/ext/curb.h +4 -4
- data/ext/curb_easy.c +344 -191
- data/ext/curb_easy.h +6 -0
- data/ext/curb_macros.h +16 -0
- data/ext/curb_multi.c +479 -103
- data/ext/curb_multi.h +8 -0
- data/ext/curb_postfield.c +134 -145
- data/ext/curb_postfield.h +10 -1
- data/ext/extconf.rb +6 -0
- data/lib/curl/easy.rb +28 -12
- data/lib/curl/multi.rb +1 -1
- data/lib/curl.rb +58 -19
- data/tests/helper.rb +122 -3
- data/tests/tc_curl_easy.rb +175 -4
- data/tests/tc_curl_easy_cookielist.rb +18 -12
- data/tests/tc_curl_maxfilesize.rb +109 -5
- data/tests/tc_curl_multi.rb +29 -0
- data/tests/tc_curl_multi_poll.rb +223 -0
- data/tests/tc_curl_multi_socket_poller.rb +374 -0
- data/tests/tc_curl_native_coverage.rb +57 -0
- data/tests/tc_curl_network_policy.rb +108 -1
- data/tests/tc_curl_postfield.rb +176 -0
- data/tests/tc_curl_protocols.rb +19 -7
- data/tests/tc_curl_transfer_guard.rb +112 -0
- data/tests/tc_fiber_scheduler.rb +101 -2
- data/tests/tc_ractor.rb +141 -0
- metadata +11 -2
data/tests/tc_ractor.rb
ADDED
|
@@ -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.
|
|
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-
|
|
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
|