curb 0.8.5 → 1.3.6
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 +7 -0
- data/README.md +579 -0
- data/Rakefile +85 -27
- data/doc.rb +48 -8
- data/ext/banned.h +32 -0
- data/ext/curb.c +563 -233
- data/ext/curb.h +19 -10
- data/ext/curb_easy.c +3229 -368
- data/ext/curb_easy.h +42 -0
- data/ext/curb_errors.c +117 -18
- data/ext/curb_errors.h +9 -5
- data/ext/curb_macros.h +33 -21
- data/ext/curb_multi.c +1904 -272
- data/ext/curb_multi.h +11 -3
- data/ext/curb_postfield.c +149 -77
- data/ext/curb_postfield.h +1 -0
- data/ext/curb_upload.c +38 -11
- data/ext/curb_upload.h +2 -0
- data/ext/extconf.rb +355 -35
- data/lib/curb.rb +1 -0
- data/lib/curl/download.rb +160 -0
- data/lib/curl/easy.rb +422 -88
- data/lib/curl/multi.rb +295 -56
- data/lib/curl.rb +676 -11
- data/tests/bug_crash_on_debug.rb +14 -28
- data/tests/bug_crash_on_progress.rb +32 -16
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +10 -15
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
- data/tests/bug_follow_redirect_288.rb +83 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
- data/tests/bug_issue102.rb +17 -0
- data/tests/bug_issue_noproxy.rb +56 -0
- data/tests/bug_issue_post_redirect.rb +93 -0
- data/tests/bug_issue_spnego.rb +41 -0
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_poison.rb +29 -0
- data/tests/bug_raise_on_callback.rb +30 -0
- data/tests/helper.rb +400 -44
- data/tests/leak_trace.rb +237 -0
- data/tests/mem_check.rb +3 -0
- data/tests/tc_curl.rb +31 -1
- data/tests/tc_curl_download.rb +98 -7
- data/tests/tc_curl_easy.rb +985 -66
- data/tests/tc_curl_easy_cookielist.rb +277 -0
- data/tests/tc_curl_easy_request_target.rb +41 -0
- data/tests/tc_curl_easy_resolve.rb +48 -0
- data/tests/tc_curl_maxfilesize.rb +212 -0
- data/tests/tc_curl_multi.rb +1111 -51
- data/tests/tc_curl_native_coverage.rb +145 -0
- data/tests/tc_curl_network_policy.rb +1475 -0
- data/tests/tc_curl_postfield.rb +207 -30
- data/tests/tc_curl_protocols.rb +388 -0
- data/tests/tc_fiber_scheduler.rb +584 -0
- data/tests/tc_ftp_options.rb +39 -0
- data/tests/tc_gc_compact.rb +223 -0
- data/tests/tc_test_server_methods.rb +110 -0
- data/tests/timeout.rb +30 -6
- metadata +66 -31
- data/README +0 -194
data/lib/curl/multi.rb
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'curl/download'
|
|
1
3
|
module Curl
|
|
2
|
-
|
|
3
4
|
class Multi
|
|
5
|
+
class DownloadError < RuntimeError
|
|
6
|
+
attr_accessor :errors
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
IDLE_EASY_REFERENCES_USE_WEAK_MAP = begin
|
|
10
|
+
probe = ObjectSpace::WeakMap.new
|
|
11
|
+
probe[Object.new.freeze] = true
|
|
12
|
+
true
|
|
13
|
+
rescue ArgumentError, FrozenError, NameError
|
|
14
|
+
false
|
|
15
|
+
end
|
|
16
|
+
|
|
4
17
|
class << self
|
|
5
18
|
# call-seq:
|
|
6
|
-
# Curl::Multi.get('url1','url2','url3','url4','url5', :follow_location => true) do|easy|
|
|
19
|
+
# Curl::Multi.get(['url1','url2','url3','url4','url5'], :follow_location => true) do|easy|
|
|
7
20
|
# easy
|
|
8
21
|
# end
|
|
9
|
-
#
|
|
22
|
+
#
|
|
10
23
|
# Blocking call to fetch multiple url's in parallel.
|
|
11
24
|
def get(urls, easy_options={}, multi_options={}, &blk)
|
|
12
25
|
url_confs = []
|
|
@@ -22,13 +35,13 @@ module Curl
|
|
|
22
35
|
# {:url => 'url2', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
|
|
23
36
|
# {:url => 'url3', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}}],
|
|
24
37
|
# { :follow_location => true, :multipart_form_post => true },
|
|
25
|
-
# {:pipeline =>
|
|
38
|
+
# {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
|
|
26
39
|
# easy_handle_on_request_complete
|
|
27
40
|
# end
|
|
28
|
-
#
|
|
41
|
+
#
|
|
29
42
|
# Blocking call to POST multiple form's in parallel.
|
|
30
|
-
#
|
|
31
|
-
# urls_with_config: is a hash of url's pointing to the postfields to send
|
|
43
|
+
#
|
|
44
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
|
32
45
|
# easy_options: are a set of common options to set on all easy handles
|
|
33
46
|
# multi_options: options to set on the Curl::Multi handle
|
|
34
47
|
#
|
|
@@ -46,13 +59,13 @@ module Curl
|
|
|
46
59
|
# {:url => 'url2', :put_data => IO.read('filepath')},
|
|
47
60
|
# {:url => 'url3', :put_data => "maybe another string or socket?"],
|
|
48
61
|
# {:follow_location => true},
|
|
49
|
-
# {:pipeline =>
|
|
62
|
+
# {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
|
|
50
63
|
# easy_handle_on_request_complete
|
|
51
64
|
# end
|
|
52
|
-
#
|
|
65
|
+
#
|
|
53
66
|
# Blocking call to POST multiple form's in parallel.
|
|
54
|
-
#
|
|
55
|
-
# urls_with_config: is a hash of url's pointing to the postfields to send
|
|
67
|
+
#
|
|
68
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
|
56
69
|
# easy_options: are a set of common options to set on all easy handles
|
|
57
70
|
# multi_options: options to set on the Curl::Multi handle
|
|
58
71
|
#
|
|
@@ -74,12 +87,12 @@ module Curl
|
|
|
74
87
|
# :follow_location => true, :max_redirects => 3 },
|
|
75
88
|
# { :url => 'url3', :method => :put, :put_data => File.open('file.txt','rb') },
|
|
76
89
|
# { :url => 'url4', :method => :head }
|
|
77
|
-
# ], {:pipeline =>
|
|
90
|
+
# ], {:pipeline => Curl::CURLPIPE_HTTP1})
|
|
78
91
|
#
|
|
79
92
|
# Blocking call to issue multiple HTTP requests with varying verb's.
|
|
80
93
|
#
|
|
81
94
|
# urls_with_config: is a hash of url's pointing to the easy handle options as well as the special option :method, that can by one of [:get, :post, :put, :delete, :head], when no verb is provided e.g. :method => nil -> GET is used
|
|
82
|
-
# multi_options: options for the multi handle
|
|
95
|
+
# multi_options: options for the multi handle
|
|
83
96
|
# blk: a callback, that yeilds when a handle is completed
|
|
84
97
|
#
|
|
85
98
|
def http(urls_with_config, multi_options={}, &blk)
|
|
@@ -92,13 +105,14 @@ module Curl
|
|
|
92
105
|
|
|
93
106
|
# configure the multi handle
|
|
94
107
|
multi_options.each { |k,v| m.send("#{k}=", v) }
|
|
95
|
-
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_body,:on_header]
|
|
108
|
+
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_redirect,:on_missing,:on_body,:on_header]
|
|
96
109
|
|
|
97
110
|
add_free_handle = proc do|conf, easy|
|
|
98
111
|
c = conf.dup # avoid being destructive to input
|
|
99
112
|
url = c.delete(:url)
|
|
100
113
|
method = c.delete(:method)
|
|
101
114
|
headers = c.delete(:headers)
|
|
115
|
+
internal_info = c.delete(:__curb_internal_info)
|
|
102
116
|
|
|
103
117
|
easy = Curl::Easy.new if easy.nil?
|
|
104
118
|
|
|
@@ -128,23 +142,29 @@ module Curl
|
|
|
128
142
|
|
|
129
143
|
# headers is a special key
|
|
130
144
|
headers.each {|k,v| easy.headers[k] = v } if headers
|
|
131
|
-
|
|
145
|
+
|
|
132
146
|
#
|
|
133
147
|
# use the remaining options as specific configuration to the easy handle
|
|
134
148
|
# bad options should raise an undefined method error
|
|
135
149
|
#
|
|
136
150
|
c.each { |k,v| easy.send("#{k}=",v) }
|
|
137
151
|
|
|
138
|
-
easy.on_complete {|curl
|
|
152
|
+
easy.on_complete {|curl|
|
|
139
153
|
free_handles << curl
|
|
140
|
-
|
|
154
|
+
if blk
|
|
155
|
+
if internal_info
|
|
156
|
+
blk.call(curl,curl.response_code,method,internal_info)
|
|
157
|
+
else
|
|
158
|
+
blk.call(curl,curl.response_code,method)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
141
161
|
}
|
|
142
162
|
m.add(easy)
|
|
143
163
|
end
|
|
144
164
|
|
|
145
165
|
max_connects.times do
|
|
146
166
|
conf = urls_with_config.pop
|
|
147
|
-
add_free_handle.call
|
|
167
|
+
add_free_handle.call(conf, nil) if conf
|
|
148
168
|
break if urls_with_config.empty?
|
|
149
169
|
end
|
|
150
170
|
|
|
@@ -153,96 +173,315 @@ module Curl
|
|
|
153
173
|
if urls_with_config.size > 0 && free_handles.size > 0
|
|
154
174
|
easy = free_handles.pop
|
|
155
175
|
conf = urls_with_config.pop
|
|
156
|
-
add_free_handle.call
|
|
176
|
+
add_free_handle.call(conf, easy) if conf
|
|
157
177
|
end
|
|
158
178
|
end
|
|
159
179
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
begin
|
|
181
|
+
if urls_with_config.empty?
|
|
182
|
+
m.perform
|
|
183
|
+
else
|
|
184
|
+
until urls_with_config.empty?
|
|
185
|
+
m.perform do
|
|
186
|
+
consume_free_handles.call
|
|
187
|
+
end
|
|
165
188
|
consume_free_handles.call
|
|
166
189
|
end
|
|
167
|
-
|
|
190
|
+
free_handles = nil
|
|
168
191
|
end
|
|
169
|
-
|
|
192
|
+
ensure
|
|
193
|
+
m.close
|
|
170
194
|
end
|
|
195
|
+
|
|
171
196
|
end
|
|
172
197
|
|
|
173
198
|
# call-seq:
|
|
174
199
|
#
|
|
175
200
|
# Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
|
|
176
201
|
#
|
|
177
|
-
# will create 2 new files file1.txt and file2.txt
|
|
178
|
-
#
|
|
202
|
+
# will create 2 new files file1.txt and file2.txt, unless either file
|
|
203
|
+
# already exists. Auto-derived filenames are safely derived from the last
|
|
204
|
+
# URL path component. Pass <tt>:download_dir</tt> as the fifth argument to
|
|
205
|
+
# treat download_paths as basenames inside a trusted directory and reject
|
|
206
|
+
# absolute, parent-directory, dotfile, and nested names.
|
|
207
|
+
#
|
|
179
208
|
# 2 files will be opened, and remain open until the call completes
|
|
180
209
|
#
|
|
181
210
|
# when using the :post or :put method, urls should be a hash, including the individual post fields per post
|
|
182
211
|
#
|
|
183
|
-
def download(urls,easy_options={},multi_options={},download_paths=nil,&blk)
|
|
212
|
+
def download(urls,easy_options={},multi_options={},download_paths=nil,download_options={},&blk)
|
|
184
213
|
errors = []
|
|
185
214
|
procs = []
|
|
186
215
|
files = []
|
|
187
216
|
urls_with_config = []
|
|
188
|
-
|
|
217
|
+
seen_download_paths = {}
|
|
218
|
+
download_infos = []
|
|
219
|
+
|
|
220
|
+
if Curl.download_options_hash?(download_paths) && download_options.empty?
|
|
221
|
+
download_options = download_paths
|
|
222
|
+
download_paths = nil
|
|
223
|
+
end
|
|
189
224
|
|
|
190
225
|
urls.each_with_index do|urlcfg,i|
|
|
191
226
|
if urlcfg.is_a?(Hash)
|
|
192
|
-
url =
|
|
227
|
+
url = urlcfg[:url]
|
|
193
228
|
else
|
|
194
229
|
url = urlcfg
|
|
195
230
|
end
|
|
196
231
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
232
|
+
download_path_arg = download_paths && download_paths[i]
|
|
233
|
+
download_path, file, safe_output, overwrite = Curl.resolve_download_output(url, download_path_arg, download_options)
|
|
234
|
+
|
|
235
|
+
if safe_output
|
|
236
|
+
expanded_path = File.expand_path(download_path)
|
|
237
|
+
raise ArgumentError, "duplicate download destination: #{download_path}" if seen_download_paths[expanded_path]
|
|
238
|
+
|
|
239
|
+
seen_download_paths[expanded_path] = true
|
|
201
240
|
end
|
|
202
241
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
file
|
|
208
|
-
|
|
242
|
+
download_infos << {
|
|
243
|
+
:url => url,
|
|
244
|
+
:urlcfg => urlcfg,
|
|
245
|
+
:path => download_path,
|
|
246
|
+
:file => file,
|
|
247
|
+
:safe_output => safe_output,
|
|
248
|
+
:overwrite => overwrite
|
|
249
|
+
}
|
|
250
|
+
end
|
|
209
251
|
|
|
210
|
-
|
|
211
|
-
|
|
252
|
+
download_infos.each do |info|
|
|
253
|
+
info[:file] ||= Curl.open_safe_download_output(info[:path], :overwrite => info[:overwrite])
|
|
254
|
+
file = info[:file]
|
|
255
|
+
procs << (lambda {|data| file.write data; data.size })
|
|
256
|
+
files << file
|
|
257
|
+
|
|
258
|
+
if info[:urlcfg].is_a?(Hash)
|
|
259
|
+
urls_with_config << info[:urlcfg].merge({:on_body => procs.last, :__curb_internal_info => info}.merge(easy_options))
|
|
212
260
|
else
|
|
213
|
-
urls_with_config << {:url => url, :on_body => procs.last, :method => :get}.merge(easy_options)
|
|
261
|
+
urls_with_config << {:url => info[:url], :on_body => procs.last, :method => :get, :__curb_internal_info => info}.merge(easy_options)
|
|
214
262
|
end
|
|
215
|
-
url_to_download_paths[url] = {:path => download_path, :file => file} # store for later
|
|
216
263
|
end
|
|
217
264
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
265
|
+
finalize_download = lambda do |curl, info|
|
|
266
|
+
file = info[:file]
|
|
267
|
+
files.reject!{|f| f == file }
|
|
268
|
+
|
|
269
|
+
if curl.last_result != 0
|
|
222
270
|
begin
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
271
|
+
if info[:safe_output]
|
|
272
|
+
file.close(false)
|
|
273
|
+
else
|
|
274
|
+
file.close
|
|
275
|
+
end
|
|
226
276
|
rescue => e
|
|
227
277
|
errors << e
|
|
228
278
|
end
|
|
279
|
+
err_class, err_summary = Curl::Easy.error(curl.last_result)
|
|
280
|
+
err_detail = curl.last_error
|
|
281
|
+
errors << err_class.new([err_summary, err_detail].compact.join(": "))
|
|
282
|
+
false
|
|
283
|
+
else
|
|
284
|
+
begin
|
|
285
|
+
if info[:safe_output]
|
|
286
|
+
file.close(true)
|
|
287
|
+
else
|
|
288
|
+
file.close
|
|
289
|
+
end
|
|
290
|
+
true
|
|
291
|
+
rescue => e
|
|
292
|
+
errors << e
|
|
293
|
+
false
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
Curl::Multi.http(urls_with_config, multi_options) do |c,code,method,info|
|
|
299
|
+
if finalize_download.call(c, info) && blk
|
|
229
300
|
blk.call(c,info[:path])
|
|
230
301
|
end
|
|
231
|
-
else
|
|
232
|
-
Curl::Multi.http(urls_with_config, multi_options)
|
|
233
302
|
end
|
|
234
303
|
|
|
235
304
|
ensure
|
|
305
|
+
pending_exception = $!
|
|
236
306
|
files.each {|f|
|
|
237
307
|
begin
|
|
238
|
-
f.
|
|
308
|
+
if f.is_a?(Curl::SafeDownloadOutput)
|
|
309
|
+
f.close(false)
|
|
310
|
+
else
|
|
311
|
+
f.close
|
|
312
|
+
end
|
|
239
313
|
rescue => e
|
|
240
314
|
errors << e
|
|
241
315
|
end
|
|
242
316
|
}
|
|
243
|
-
|
|
317
|
+
if errors.any? && !pending_exception
|
|
318
|
+
de = Curl::Multi::DownloadError.new
|
|
319
|
+
de.errors = errors
|
|
320
|
+
raise de
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def cancel!
|
|
326
|
+
requests.each do |_,easy|
|
|
327
|
+
remove(easy)
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def idle?
|
|
332
|
+
requests.empty?
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def requests
|
|
336
|
+
@requests ||= {}
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def __curb_native_safety_signatures
|
|
340
|
+
@__curb_native_safety_signatures ||= {}
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def __curb_safety_signature_for(easy)
|
|
344
|
+
safety_signature = if Curl.respond_to?(:safety_signature_for, true)
|
|
345
|
+
Curl.__send__(:safety_signature_for, easy)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
[
|
|
349
|
+
safety_signature,
|
|
350
|
+
easy.respond_to?(:network_policy) ? easy.network_policy : nil,
|
|
351
|
+
easy.respond_to?(:allowed_hosts) ? easy.allowed_hosts : nil,
|
|
352
|
+
easy.respond_to?(:allowed_cidrs) ? easy.allowed_cidrs : nil
|
|
353
|
+
]
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def __record_native_safety_signature(easy)
|
|
357
|
+
__curb_native_safety_signatures[easy.object_id] = __curb_safety_signature_for(easy)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def __idle_easy_references
|
|
361
|
+
@__curb_idle_easy_references ||= __new_idle_easy_references
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def __register_idle_easy_reference(easy)
|
|
365
|
+
if IDLE_EASY_REFERENCES_USE_WEAK_MAP
|
|
366
|
+
__idle_easy_references[easy] = true
|
|
367
|
+
else
|
|
368
|
+
__idle_easy_references[easy.object_id] = true
|
|
244
369
|
end
|
|
370
|
+
self
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def __unregister_idle_easy_reference(easy)
|
|
374
|
+
return self unless instance_variable_defined?(:@__curb_idle_easy_references)
|
|
375
|
+
|
|
376
|
+
if !IDLE_EASY_REFERENCES_USE_WEAK_MAP
|
|
377
|
+
@__curb_idle_easy_references.delete(easy.object_id)
|
|
378
|
+
elsif @__curb_idle_easy_references.respond_to?(:delete)
|
|
379
|
+
@__curb_idle_easy_references.delete(easy)
|
|
380
|
+
else
|
|
381
|
+
retained_references = ObjectSpace::WeakMap.new
|
|
382
|
+
@__curb_idle_easy_references.each_key do |tracked_easy|
|
|
383
|
+
next if tracked_easy.equal?(easy)
|
|
245
384
|
|
|
385
|
+
retained_references[tracked_easy] = true
|
|
386
|
+
end
|
|
387
|
+
@__curb_idle_easy_references = retained_references
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
self
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def __clear_idle_easy_references
|
|
394
|
+
return unless instance_variable_defined?(:@__curb_idle_easy_references)
|
|
395
|
+
|
|
396
|
+
if IDLE_EASY_REFERENCES_USE_WEAK_MAP
|
|
397
|
+
@__curb_idle_easy_references.keys.each do |easy|
|
|
398
|
+
easy.multi = nil if easy.multi.equal?(self)
|
|
399
|
+
end
|
|
400
|
+
else
|
|
401
|
+
@__curb_idle_easy_references.keys.each do |easy_object_id|
|
|
402
|
+
begin
|
|
403
|
+
easy = ObjectSpace._id2ref(easy_object_id)
|
|
404
|
+
rescue RangeError
|
|
405
|
+
next
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
next unless easy.is_a?(Curl::Easy)
|
|
409
|
+
|
|
410
|
+
easy.multi = nil if easy.multi.equal?(self)
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
@__curb_idle_easy_references = __new_idle_easy_references
|
|
246
414
|
end
|
|
415
|
+
|
|
416
|
+
def __new_idle_easy_references
|
|
417
|
+
IDLE_EASY_REFERENCES_USE_WEAK_MAP ? ObjectSpace::WeakMap.new : {}
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
private :__idle_easy_references, :__curb_native_safety_signatures,
|
|
421
|
+
:__curb_safety_signature_for, :__record_native_safety_signature,
|
|
422
|
+
:__register_idle_easy_reference,
|
|
423
|
+
:__unregister_idle_easy_reference, :__clear_idle_easy_references,
|
|
424
|
+
:__new_idle_easy_references
|
|
425
|
+
|
|
426
|
+
alias_method :_curb_native_perform, :perform
|
|
427
|
+
|
|
428
|
+
def perform(*args, &block)
|
|
429
|
+
requests.each_value do |easy|
|
|
430
|
+
Curl.__send__(:apply_safety!, easy) if Curl.respond_to?(:apply_safety!, true)
|
|
431
|
+
signature = __curb_safety_signature_for(easy)
|
|
432
|
+
if __curb_native_safety_signatures[easy.object_id] != signature &&
|
|
433
|
+
easy.respond_to?(:__curb_native_setup!, true)
|
|
434
|
+
easy.__send__(:__curb_native_setup!)
|
|
435
|
+
__curb_native_safety_signatures[easy.object_id] = signature
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
_curb_native_perform(*args, &block)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def add(easy)
|
|
443
|
+
return self if requests[easy.object_id]
|
|
444
|
+
# Once a deferred callback exception is pending, Multi#perform is
|
|
445
|
+
# draining existing transfers only and must not start replacement work.
|
|
446
|
+
return self if instance_variable_defined?(:@__curb_deferred_exception)
|
|
447
|
+
Curl.__send__(:apply_safety!, easy) if Curl.respond_to?(:apply_safety!, true)
|
|
448
|
+
_add(easy)
|
|
449
|
+
__unregister_idle_easy_reference(easy)
|
|
450
|
+
requests[easy.object_id] = easy
|
|
451
|
+
__record_native_safety_signature(easy)
|
|
452
|
+
self
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def remove(easy)
|
|
456
|
+
return self if !requests[easy.object_id]
|
|
457
|
+
requests.delete(easy.object_id)
|
|
458
|
+
__curb_native_safety_signatures.delete(easy.object_id)
|
|
459
|
+
_remove(easy)
|
|
460
|
+
self
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def close
|
|
464
|
+
__close(true)
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def _autoclose
|
|
468
|
+
__close(false)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
private :_autoclose
|
|
472
|
+
|
|
473
|
+
private
|
|
474
|
+
|
|
475
|
+
def __close(permanent)
|
|
476
|
+
requests.values.each {|easy|
|
|
477
|
+
_remove(easy)
|
|
478
|
+
}
|
|
479
|
+
__clear_idle_easy_references if permanent
|
|
480
|
+
@requests = {}
|
|
481
|
+
_close
|
|
482
|
+
_mark_closed if permanent
|
|
483
|
+
self
|
|
484
|
+
end
|
|
485
|
+
|
|
247
486
|
end
|
|
248
487
|
end
|