curb 1.2.2 → 1.3.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/Rakefile +22 -0
- data/ext/curb.c +282 -231
- data/ext/curb.h +4 -4
- data/ext/curb_easy.c +608 -215
- data/ext/curb_easy.h +5 -0
- data/ext/curb_errors.c +5 -5
- data/ext/curb_errors.h +1 -1
- data/ext/curb_macros.h +14 -14
- data/ext/curb_multi.c +612 -142
- data/ext/curb_multi.h +3 -1
- data/ext/curb_postfield.c +47 -21
- data/ext/curb_postfield.h +1 -0
- data/ext/curb_upload.c +32 -9
- data/ext/curb_upload.h +2 -0
- data/ext/extconf.rb +42 -1
- data/lib/curl/easy.rb +154 -13
- data/lib/curl/multi.rb +69 -9
- data/lib/curl.rb +193 -0
- data/tests/helper.rb +222 -36
- data/tests/leak_trace.rb +237 -0
- data/tests/tc_curl_download.rb +6 -2
- data/tests/tc_curl_easy.rb +450 -1
- data/tests/tc_curl_multi.rb +573 -59
- data/tests/tc_curl_native_coverage.rb +130 -0
- data/tests/tc_curl_postfield.rb +161 -0
- data/tests/tc_fiber_scheduler.rb +342 -7
- data/tests/tc_gc_compact.rb +178 -16
- data/tests/tc_test_server_methods.rb +110 -0
- metadata +10 -14
- data/tests/test_basic.rb +0 -29
- data/tests/test_fiber_debug.rb +0 -69
- data/tests/test_fiber_simple.rb +0 -65
- data/tests/test_real_url.rb +0 -65
- data/tests/test_simple_fiber.rb +0 -34
data/ext/curb_multi.h
CHANGED
|
@@ -15,13 +15,15 @@ struct st_table;
|
|
|
15
15
|
typedef struct {
|
|
16
16
|
int active;
|
|
17
17
|
int running;
|
|
18
|
+
char closed;
|
|
18
19
|
CURLM *handle;
|
|
19
20
|
struct st_table *attached;
|
|
20
21
|
} ruby_curl_multi;
|
|
21
22
|
|
|
22
23
|
extern VALUE cCurlMulti;
|
|
24
|
+
extern const rb_data_type_t ruby_curl_multi_data_type;
|
|
25
|
+
|
|
23
26
|
void init_curb_multi();
|
|
24
|
-
VALUE ruby_curl_multi_new(VALUE klass);
|
|
25
27
|
void rb_curl_multi_forget_easy(ruby_curl_multi *rbcm, void *rbce_ptr);
|
|
26
28
|
|
|
27
29
|
|
data/ext/curb_postfield.c
CHANGED
|
@@ -32,7 +32,7 @@ void append_to_form(VALUE self,
|
|
|
32
32
|
ruby_curl_postfield *rbcpf;
|
|
33
33
|
CURLFORMcode result = -1;
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
TypedData_Get_Struct(self, ruby_curl_postfield, &ruby_curl_postfield_data_type, rbcpf);
|
|
36
36
|
|
|
37
37
|
if (rbcpf->name == Qnil) {
|
|
38
38
|
rb_raise(eCurlErrInvalidPostField, "Cannot post unnamed field");
|
|
@@ -177,19 +177,43 @@ void append_to_form(VALUE self,
|
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
/* ================== MARK/FREE FUNC ==================*/
|
|
180
|
-
void curl_postfield_mark(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
static void curl_postfield_mark(void *ptr) {
|
|
181
|
+
ruby_curl_postfield *rbcpf = (ruby_curl_postfield *)ptr;
|
|
182
|
+
if (rbcpf) {
|
|
183
|
+
rb_gc_mark(rbcpf->name);
|
|
184
|
+
rb_gc_mark(rbcpf->content);
|
|
185
|
+
rb_gc_mark(rbcpf->content_type);
|
|
186
|
+
rb_gc_mark(rbcpf->local_file);
|
|
187
|
+
rb_gc_mark(rbcpf->remote_file);
|
|
188
|
+
rb_gc_mark(rbcpf->buffer_str);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static void curl_postfield_free(void *ptr) {
|
|
193
|
+
if (ptr) free(ptr);
|
|
187
194
|
}
|
|
188
195
|
|
|
189
|
-
|
|
190
|
-
|
|
196
|
+
static size_t curl_postfield_memsize(const void *ptr) {
|
|
197
|
+
(void)ptr;
|
|
198
|
+
return sizeof(ruby_curl_postfield);
|
|
191
199
|
}
|
|
192
200
|
|
|
201
|
+
const rb_data_type_t ruby_curl_postfield_data_type = {
|
|
202
|
+
"Curl::PostField",
|
|
203
|
+
{
|
|
204
|
+
curl_postfield_mark,
|
|
205
|
+
curl_postfield_free,
|
|
206
|
+
curl_postfield_memsize,
|
|
207
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
208
|
+
NULL, /* compact */
|
|
209
|
+
#endif
|
|
210
|
+
},
|
|
211
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
212
|
+
NULL, NULL, /* parent, data */
|
|
213
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
|
214
|
+
#endif
|
|
215
|
+
};
|
|
216
|
+
|
|
193
217
|
|
|
194
218
|
/* ================= ALLOC METHODS ====================*/
|
|
195
219
|
|
|
@@ -208,10 +232,11 @@ void curl_postfield_free(ruby_curl_postfield *rbcpf) {
|
|
|
208
232
|
* data.
|
|
209
233
|
*/
|
|
210
234
|
static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
235
|
+
VALUE self;
|
|
236
|
+
ruby_curl_postfield *rbcpf;
|
|
237
|
+
|
|
238
|
+
self = TypedData_Make_Struct(klass, ruby_curl_postfield, &ruby_curl_postfield_data_type, rbcpf);
|
|
239
|
+
MEMZERO(rbcpf, ruby_curl_postfield, 1);
|
|
215
240
|
|
|
216
241
|
// wierdness - we actually require two args, unless a block is provided, but
|
|
217
242
|
// we have to work that out below.
|
|
@@ -239,7 +264,7 @@ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass)
|
|
|
239
264
|
rbcpf->remote_file = Qnil;
|
|
240
265
|
rbcpf->buffer_str = Qnil;
|
|
241
266
|
|
|
242
|
-
return
|
|
267
|
+
return self;
|
|
243
268
|
}
|
|
244
269
|
|
|
245
270
|
/*
|
|
@@ -257,10 +282,11 @@ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass)
|
|
|
257
282
|
*/
|
|
258
283
|
static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
|
|
259
284
|
// TODO needs to handle content-type too
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
285
|
+
VALUE self;
|
|
286
|
+
ruby_curl_postfield *rbcpf;
|
|
287
|
+
|
|
288
|
+
self = TypedData_Make_Struct(klass, ruby_curl_postfield, &ruby_curl_postfield_data_type, rbcpf);
|
|
289
|
+
MEMZERO(rbcpf, ruby_curl_postfield, 1);
|
|
264
290
|
|
|
265
291
|
rb_scan_args(argc, argv, "21&", &rbcpf->name, &rbcpf->local_file, &rbcpf->remote_file, &rbcpf->content_proc);
|
|
266
292
|
|
|
@@ -288,7 +314,7 @@ static VALUE ruby_curl_postfield_new_file(int argc, VALUE *argv, VALUE klass) {
|
|
|
288
314
|
rbcpf->content_type = Qnil;
|
|
289
315
|
rbcpf->buffer_str = Qnil;
|
|
290
316
|
|
|
291
|
-
return
|
|
317
|
+
return self;
|
|
292
318
|
}
|
|
293
319
|
|
|
294
320
|
/* ================= ATTRIBUTES ====================*/
|
|
@@ -435,7 +461,7 @@ static VALUE ruby_curl_postfield_to_str(VALUE self) {
|
|
|
435
461
|
CURL *curl_handle = NULL;
|
|
436
462
|
#endif
|
|
437
463
|
|
|
438
|
-
|
|
464
|
+
TypedData_Get_Struct(self, ruby_curl_postfield, &ruby_curl_postfield_data_type, rbcpf);
|
|
439
465
|
|
|
440
466
|
if (rbcpf->name != Qnil) {
|
|
441
467
|
name = rbcpf->name;
|
data/ext/curb_postfield.h
CHANGED
data/ext/curb_upload.c
CHANGED
|
@@ -10,13 +10,36 @@ VALUE cCurlUpload;
|
|
|
10
10
|
mCurl = rb_define_module("Curl");
|
|
11
11
|
#endif
|
|
12
12
|
|
|
13
|
-
static void curl_upload_mark(
|
|
14
|
-
|
|
13
|
+
static void curl_upload_mark(void *ptr) {
|
|
14
|
+
ruby_curl_upload *rbcu = (ruby_curl_upload *)ptr;
|
|
15
|
+
if (rbcu && rbcu->stream && !NIL_P(rbcu->stream)) rb_gc_mark(rbcu->stream);
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
static void curl_upload_free(void *ptr) {
|
|
19
|
+
if (ptr) free(ptr);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static size_t curl_upload_memsize(const void *ptr) {
|
|
23
|
+
(void)ptr;
|
|
24
|
+
return sizeof(ruby_curl_upload);
|
|
18
25
|
}
|
|
19
26
|
|
|
27
|
+
const rb_data_type_t ruby_curl_upload_data_type = {
|
|
28
|
+
"Curl::Upload",
|
|
29
|
+
{
|
|
30
|
+
curl_upload_mark,
|
|
31
|
+
curl_upload_free,
|
|
32
|
+
curl_upload_memsize,
|
|
33
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
34
|
+
NULL, /* compact */
|
|
35
|
+
#endif
|
|
36
|
+
},
|
|
37
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
38
|
+
NULL, NULL, /* parent, data */
|
|
39
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
|
40
|
+
#endif
|
|
41
|
+
};
|
|
42
|
+
|
|
20
43
|
/*
|
|
21
44
|
* call-seq:
|
|
22
45
|
* internal class for sending large file uploads
|
|
@@ -29,7 +52,7 @@ VALUE ruby_curl_upload_new(VALUE klass) {
|
|
|
29
52
|
}
|
|
30
53
|
rbcu->stream = Qnil;
|
|
31
54
|
rbcu->offset = 0;
|
|
32
|
-
upload =
|
|
55
|
+
upload = TypedData_Wrap_Struct(klass, &ruby_curl_upload_data_type, rbcu);
|
|
33
56
|
return upload;
|
|
34
57
|
}
|
|
35
58
|
|
|
@@ -39,7 +62,7 @@ VALUE ruby_curl_upload_new(VALUE klass) {
|
|
|
39
62
|
*/
|
|
40
63
|
VALUE ruby_curl_upload_stream_set(VALUE self, VALUE stream) {
|
|
41
64
|
ruby_curl_upload *rbcu;
|
|
42
|
-
|
|
65
|
+
TypedData_Get_Struct(self, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
43
66
|
rbcu->stream = stream;
|
|
44
67
|
return stream;
|
|
45
68
|
}
|
|
@@ -49,7 +72,7 @@ VALUE ruby_curl_upload_stream_set(VALUE self, VALUE stream) {
|
|
|
49
72
|
*/
|
|
50
73
|
VALUE ruby_curl_upload_stream_get(VALUE self) {
|
|
51
74
|
ruby_curl_upload *rbcu;
|
|
52
|
-
|
|
75
|
+
TypedData_Get_Struct(self, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
53
76
|
return rbcu->stream;
|
|
54
77
|
}
|
|
55
78
|
/*
|
|
@@ -58,7 +81,7 @@ VALUE ruby_curl_upload_stream_get(VALUE self) {
|
|
|
58
81
|
*/
|
|
59
82
|
VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset) {
|
|
60
83
|
ruby_curl_upload *rbcu;
|
|
61
|
-
|
|
84
|
+
TypedData_Get_Struct(self, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
62
85
|
rbcu->offset = NUM2LONG(offset);
|
|
63
86
|
return offset;
|
|
64
87
|
}
|
|
@@ -68,7 +91,7 @@ VALUE ruby_curl_upload_offset_set(VALUE self, VALUE offset) {
|
|
|
68
91
|
*/
|
|
69
92
|
VALUE ruby_curl_upload_offset_get(VALUE self) {
|
|
70
93
|
ruby_curl_upload *rbcu;
|
|
71
|
-
|
|
94
|
+
TypedData_Get_Struct(self, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
72
95
|
return LONG2NUM(rbcu->offset);
|
|
73
96
|
}
|
|
74
97
|
|
data/ext/curb_upload.h
CHANGED
data/ext/extconf.rb
CHANGED
|
@@ -299,6 +299,38 @@ have_constant "curlopt_sockoptdata"
|
|
|
299
299
|
have_constant "curlopt_opensocketfunction"
|
|
300
300
|
have_constant "curlopt_opensocketdata"
|
|
301
301
|
|
|
302
|
+
# Deprecated constants (still check for them for backward compat)
|
|
303
|
+
have_constant "curlopt_ioctlfunction"
|
|
304
|
+
have_constant "curlopt_ioctldata"
|
|
305
|
+
have_constant "curlopt_progressfunction"
|
|
306
|
+
have_constant "curlopt_progressdata"
|
|
307
|
+
have_constant "curlopt_conv_to_network_function"
|
|
308
|
+
have_constant "curlopt_conv_from_network_function"
|
|
309
|
+
have_constant "curlopt_conv_from_utf8_function"
|
|
310
|
+
|
|
311
|
+
# Replacements for deprecated constants
|
|
312
|
+
# CURLOPT_PROGRESSFUNCTION -> CURLOPT_XFERINFOFUNCTION (since 7.32.0)
|
|
313
|
+
have_constant "curlopt_xferinfofunction"
|
|
314
|
+
have_constant "curlopt_xferinfodata"
|
|
315
|
+
|
|
316
|
+
# CURLOPT_PROTOCOLS -> CURLOPT_PROTOCOLS_STR (since 7.85.0)
|
|
317
|
+
have_constant "curlopt_protocols_str"
|
|
318
|
+
have_constant "curlopt_redir_protocols_str"
|
|
319
|
+
|
|
320
|
+
# CURLOPT_SOCKS5_GSSAPI_SERVICE -> CURLOPT_PROXY_SERVICE_NAME (since 7.49.0)
|
|
321
|
+
have_constant "curlopt_proxy_service_name"
|
|
322
|
+
|
|
323
|
+
# CURLOPT_HTTPPOST -> CURLOPT_MIMEPOST (since 7.56.0)
|
|
324
|
+
have_constant "curlopt_mimepost"
|
|
325
|
+
|
|
326
|
+
# CURLINFO_* -> CURLINFO_*_T (since 7.55.0)
|
|
327
|
+
have_constant "curlinfo_size_upload_t"
|
|
328
|
+
have_constant "curlinfo_size_download_t"
|
|
329
|
+
have_constant "curlinfo_speed_upload_t"
|
|
330
|
+
have_constant "curlinfo_speed_download_t"
|
|
331
|
+
have_constant "curlinfo_content_length_download_t"
|
|
332
|
+
have_constant "curlinfo_content_length_upload_t"
|
|
333
|
+
|
|
302
334
|
# additional consts
|
|
303
335
|
have_constant "curle_conv_failed"
|
|
304
336
|
have_constant "curle_conv_reqd"
|
|
@@ -621,6 +653,14 @@ if try_compile('int main() { return 0; }','-Wall')
|
|
|
621
653
|
$CFLAGS << ' -Wall'
|
|
622
654
|
end
|
|
623
655
|
|
|
656
|
+
# Clang-specific warning suppressions (not recognized by GCC)
|
|
657
|
+
# These are used to suppress warnings in Ruby header macros
|
|
658
|
+
%w[-Wno-self-assign -Wno-parentheses-equality -Wno-constant-logical-operand].each do |flag|
|
|
659
|
+
if try_compile('int main() { return 0; }', flag)
|
|
660
|
+
$CFLAGS << " #{flag}"
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
|
|
624
664
|
# do some checking to detect ruby 1.8 hash.c vs ruby 1.9 hash.c
|
|
625
665
|
def test_for(name, const, src)
|
|
626
666
|
checking_for name do
|
|
@@ -645,7 +685,8 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
|
|
|
645
685
|
have_func('rb_thread_blocking_region')
|
|
646
686
|
have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
|
647
687
|
have_header('ruby/io.h')
|
|
648
|
-
|
|
688
|
+
# Ruby 4.x exports rb_thread_fd_select without declaring it in ruby/io.h.
|
|
689
|
+
have_func('rb_thread_fd_select')
|
|
649
690
|
have_func('rb_wait_for_single_fd', 'ruby/io.h')
|
|
650
691
|
have_header('ruby/fiber/scheduler.h')
|
|
651
692
|
have_func('rb_fiber_scheduler_current', 'ruby/fiber/scheduler.h')
|
data/lib/curl/easy.rb
CHANGED
|
@@ -1,7 +1,106 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
module Curl
|
|
3
3
|
class Easy
|
|
4
|
+
class << self
|
|
5
|
+
def deferred_multi_close_mutex
|
|
6
|
+
@deferred_multi_close_mutex ||= Mutex.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def deferred_multi_closes
|
|
10
|
+
deferred_multi_close_mutex.synchronize do
|
|
11
|
+
(@deferred_multi_closes ||= []).dup
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def release_deferred_multi_close(multi, easy)
|
|
16
|
+
if easy && multi.requests[easy.object_id]
|
|
17
|
+
begin
|
|
18
|
+
multi.remove(easy)
|
|
19
|
+
rescue StandardError
|
|
20
|
+
# Deferred cleanup only applies to implicit single-easy multis, so
|
|
21
|
+
# clear any stale Ruby bookkeeping and continue closing the handle.
|
|
22
|
+
multi.instance_variable_set(:@requests, {})
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
multi.instance_variable_set(:@requests, {})
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
multi.instance_variable_set(:@deferred_close, false)
|
|
29
|
+
multi._close
|
|
30
|
+
true
|
|
31
|
+
rescue StandardError
|
|
32
|
+
false
|
|
33
|
+
end
|
|
4
34
|
|
|
35
|
+
def defer_multi_close(multi, easy, owner: Thread.current)
|
|
36
|
+
deferred_multi_close_mutex.synchronize do
|
|
37
|
+
@deferred_multi_closes ||= []
|
|
38
|
+
return if @deferred_multi_closes.any? { |entry| entry[:multi].equal?(multi) }
|
|
39
|
+
|
|
40
|
+
multi.instance_variable_set(:@deferred_close, true)
|
|
41
|
+
@deferred_multi_closes << { multi: multi, easy: easy, owner: owner }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def flush_deferred_multi_closes(all_threads: false)
|
|
46
|
+
pending = deferred_multi_close_mutex.synchronize do
|
|
47
|
+
@deferred_multi_closes ||= []
|
|
48
|
+
|
|
49
|
+
if all_threads
|
|
50
|
+
@deferred_multi_closes.shift(@deferred_multi_closes.length)
|
|
51
|
+
else
|
|
52
|
+
owner = Thread.current
|
|
53
|
+
remaining = []
|
|
54
|
+
current = []
|
|
55
|
+
|
|
56
|
+
@deferred_multi_closes.each do |entry|
|
|
57
|
+
if entry[:owner].equal?(owner)
|
|
58
|
+
current << entry
|
|
59
|
+
else
|
|
60
|
+
remaining << entry
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
@deferred_multi_closes = remaining
|
|
65
|
+
current
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
pending.each do |entry|
|
|
70
|
+
multi = entry[:multi]
|
|
71
|
+
easy = entry[:easy]
|
|
72
|
+
|
|
73
|
+
unless release_deferred_multi_close(multi, easy)
|
|
74
|
+
defer_multi_close(multi, easy, owner: entry[:owner])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
at_exit do
|
|
81
|
+
flush_deferred_multi_closes(all_threads: true)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
alias_method :_curb_native_close, :close
|
|
85
|
+
alias_method :_curb_native_multi_set, :multi=
|
|
86
|
+
|
|
87
|
+
def close
|
|
88
|
+
previous_multi = self.multi
|
|
89
|
+
result = _curb_native_close
|
|
90
|
+
previous_multi.__send__(:__unregister_idle_easy_reference, self) if previous_multi
|
|
91
|
+
result
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def multi=(multi)
|
|
95
|
+
previous_multi = self.multi
|
|
96
|
+
return multi if previous_multi.equal?(multi)
|
|
97
|
+
|
|
98
|
+
result = _curb_native_multi_set(multi)
|
|
99
|
+
previous_multi.__send__(:__unregister_idle_easy_reference, self) if previous_multi
|
|
100
|
+
multi.__send__(:__register_idle_easy_reference, self) if multi
|
|
101
|
+
result
|
|
102
|
+
end
|
|
103
|
+
|
|
5
104
|
alias post http_post
|
|
6
105
|
alias put http_put
|
|
7
106
|
alias body body_str
|
|
@@ -64,18 +163,55 @@ module Curl
|
|
|
64
163
|
# the configured HTTP Verb.
|
|
65
164
|
#
|
|
66
165
|
def perform
|
|
67
|
-
self.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
166
|
+
self.class.flush_deferred_multi_closes
|
|
167
|
+
|
|
168
|
+
if Curl.scheduler_active? && self.multi.nil?
|
|
169
|
+
ret = Curl.perform_with_scheduler(self)
|
|
170
|
+
else
|
|
171
|
+
multi = self.multi
|
|
172
|
+
created_multi = multi.nil?
|
|
173
|
+
raised = false
|
|
174
|
+
|
|
175
|
+
if created_multi
|
|
176
|
+
multi = Curl::Multi.new
|
|
177
|
+
self.multi = multi
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
begin
|
|
181
|
+
multi.add(self)
|
|
182
|
+
ret = multi.perform
|
|
183
|
+
multi.remove(self) if self.multi == multi
|
|
184
|
+
rescue Exception
|
|
185
|
+
raised = true
|
|
186
|
+
raise
|
|
187
|
+
ensure
|
|
188
|
+
if created_multi
|
|
189
|
+
if raised
|
|
190
|
+
unless self.class.release_deferred_multi_close(multi, self)
|
|
191
|
+
self.class.defer_multi_close(multi, self)
|
|
192
|
+
end
|
|
193
|
+
self.multi = nil if self.multi == multi
|
|
194
|
+
elsif Curl::Multi.autoclose
|
|
195
|
+
multi.__send__(:_autoclose)
|
|
196
|
+
self.multi = nil if self.multi == multi
|
|
197
|
+
else
|
|
198
|
+
self.multi = multi
|
|
199
|
+
end
|
|
200
|
+
elsif Curl::Multi.autoclose
|
|
201
|
+
multi.__send__(:_autoclose)
|
|
202
|
+
self.multi = nil if self.multi == multi
|
|
203
|
+
else
|
|
204
|
+
self.multi = multi
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
if (callback_error = _take_callback_error)
|
|
210
|
+
raise callback_error
|
|
75
211
|
end
|
|
76
212
|
|
|
77
213
|
if self.last_result != 0 && self.on_failure.nil?
|
|
78
|
-
|
|
214
|
+
err_class, err_summary = Curl::Easy.error(self.last_result)
|
|
79
215
|
err_detail = self.last_error
|
|
80
216
|
raise err_class.new([err_summary, err_detail].compact.join(": "))
|
|
81
217
|
end
|
|
@@ -85,6 +221,7 @@ module Curl
|
|
|
85
221
|
|
|
86
222
|
#
|
|
87
223
|
# call-seq:
|
|
224
|
+
|
|
88
225
|
#
|
|
89
226
|
# easy = Curl::Easy.new
|
|
90
227
|
# easy.nosignal = true
|
|
@@ -109,12 +246,16 @@ module Curl
|
|
|
109
246
|
#
|
|
110
247
|
# easy = Curl::Easy.new("url")
|
|
111
248
|
# easy.version = Curl::HTTP_2_0
|
|
112
|
-
# easy.
|
|
113
|
-
# easy.
|
|
114
|
-
# easy.
|
|
249
|
+
# easy.http_version = Curl::HTTP_1_1
|
|
250
|
+
# easy.http_version = Curl::HTTP_1_0
|
|
251
|
+
# easy.http_version = Curl::HTTP_NONE
|
|
115
252
|
#
|
|
116
253
|
def version=(http_version)
|
|
117
|
-
|
|
254
|
+
self.http_version = http_version
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def version
|
|
258
|
+
http_version
|
|
118
259
|
end
|
|
119
260
|
|
|
120
261
|
#
|
data/lib/curl/multi.rb
CHANGED
|
@@ -160,16 +160,20 @@ module Curl
|
|
|
160
160
|
end
|
|
161
161
|
end
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
begin
|
|
164
|
+
if urls_with_config.empty?
|
|
165
|
+
m.perform
|
|
166
|
+
else
|
|
167
|
+
until urls_with_config.empty?
|
|
168
|
+
m.perform do
|
|
169
|
+
consume_free_handles.call
|
|
170
|
+
end
|
|
168
171
|
consume_free_handles.call
|
|
169
172
|
end
|
|
170
|
-
|
|
173
|
+
free_handles = nil
|
|
171
174
|
end
|
|
172
|
-
|
|
175
|
+
ensure
|
|
176
|
+
m.close
|
|
173
177
|
end
|
|
174
178
|
|
|
175
179
|
end
|
|
@@ -266,10 +270,53 @@ module Curl
|
|
|
266
270
|
@requests ||= {}
|
|
267
271
|
end
|
|
268
272
|
|
|
273
|
+
def __idle_easy_references
|
|
274
|
+
@__curb_idle_easy_references ||= ObjectSpace::WeakMap.new
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def __register_idle_easy_reference(easy)
|
|
278
|
+
__idle_easy_references[easy] = true
|
|
279
|
+
self
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def __unregister_idle_easy_reference(easy)
|
|
283
|
+
return self unless instance_variable_defined?(:@__curb_idle_easy_references)
|
|
284
|
+
|
|
285
|
+
if @__curb_idle_easy_references.respond_to?(:delete)
|
|
286
|
+
@__curb_idle_easy_references.delete(easy)
|
|
287
|
+
else
|
|
288
|
+
retained_references = ObjectSpace::WeakMap.new
|
|
289
|
+
@__curb_idle_easy_references.each_key do |tracked_easy|
|
|
290
|
+
next if tracked_easy.equal?(easy)
|
|
291
|
+
|
|
292
|
+
retained_references[tracked_easy] = true
|
|
293
|
+
end
|
|
294
|
+
@__curb_idle_easy_references = retained_references
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
self
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def __clear_idle_easy_references
|
|
301
|
+
return unless instance_variable_defined?(:@__curb_idle_easy_references)
|
|
302
|
+
|
|
303
|
+
@__curb_idle_easy_references.keys.each do |easy|
|
|
304
|
+
easy.multi = nil if easy.multi.equal?(self)
|
|
305
|
+
end
|
|
306
|
+
@__curb_idle_easy_references = ObjectSpace::WeakMap.new
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
private :__idle_easy_references, :__register_idle_easy_reference,
|
|
310
|
+
:__unregister_idle_easy_reference, :__clear_idle_easy_references
|
|
311
|
+
|
|
269
312
|
def add(easy)
|
|
270
313
|
return self if requests[easy.object_id]
|
|
271
|
-
|
|
314
|
+
# Once a deferred callback exception is pending, Multi#perform is
|
|
315
|
+
# draining existing transfers only and must not start replacement work.
|
|
316
|
+
return self if instance_variable_defined?(:@__curb_deferred_exception)
|
|
272
317
|
_add(easy)
|
|
318
|
+
__unregister_idle_easy_reference(easy)
|
|
319
|
+
requests[easy.object_id] = easy
|
|
273
320
|
self
|
|
274
321
|
end
|
|
275
322
|
|
|
@@ -281,14 +328,27 @@ module Curl
|
|
|
281
328
|
end
|
|
282
329
|
|
|
283
330
|
def close
|
|
331
|
+
__close(true)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def _autoclose
|
|
335
|
+
__close(false)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
private :_autoclose
|
|
339
|
+
|
|
340
|
+
private
|
|
341
|
+
|
|
342
|
+
def __close(permanent)
|
|
284
343
|
requests.values.each {|easy|
|
|
285
344
|
_remove(easy)
|
|
286
345
|
}
|
|
346
|
+
__clear_idle_easy_references if permanent
|
|
287
347
|
@requests = {}
|
|
288
348
|
_close
|
|
349
|
+
_mark_closed if permanent
|
|
289
350
|
self
|
|
290
351
|
end
|
|
291
352
|
|
|
292
|
-
|
|
293
353
|
end
|
|
294
354
|
end
|