curb 0.9.8 → 1.0.5
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/README.markdown +69 -7
- data/Rakefile +18 -19
- data/ext/banned.h +32 -0
- data/ext/curb.c +164 -8
- data/ext/curb.h +18 -5
- data/ext/curb_easy.c +134 -44
- data/ext/curb_easy.h +3 -0
- data/ext/curb_macros.h +12 -0
- data/ext/curb_multi.c +50 -24
- data/ext/curb_postfield.c +9 -7
- data/ext/curb_upload.c +1 -0
- data/ext/extconf.rb +45 -0
- data/lib/curb.rb +1 -0
- data/lib/curl/easy.rb +14 -7
- data/lib/curl/multi.rb +11 -3
- data/lib/curl.rb +12 -3
- data/tests/bug_crash_on_debug.rb +14 -28
- data/tests/bug_crash_on_progress.rb +7 -31
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +8 -13
- 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_issue277.rb +32 -0
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_raise_on_callback.rb +29 -0
- data/tests/helper.rb +27 -1
- data/tests/tc_curl_easy.rb +72 -4
- data/tests/tc_curl_maxfilesize.rb +12 -0
- data/tests/tc_curl_multi.rb +98 -16
- data/tests/tc_curl_postfield.rb +29 -29
- data/tests/tc_curl_protocols.rb +37 -0
- data/tests/timeout.rb +21 -5
- metadata +37 -27
data/ext/curb_multi.c
CHANGED
@@ -43,8 +43,25 @@ static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy);
|
|
43
43
|
static void rb_curl_multi_read_info(VALUE self, CURLM *mptr);
|
44
44
|
static void rb_curl_multi_run(VALUE self, CURLM *multi_handle, int *still_running);
|
45
45
|
|
46
|
-
static VALUE callback_exception(VALUE
|
47
|
-
|
46
|
+
static VALUE callback_exception(VALUE did_raise, VALUE exception) {
|
47
|
+
// TODO: we could have an option to enable exception reporting
|
48
|
+
/* VALUE ret = rb_funcall(exception, rb_intern("message"), 0);
|
49
|
+
VALUE trace = rb_funcall(exception, rb_intern("backtrace"), 0);
|
50
|
+
if (RB_TYPE_P(trace, T_ARRAY) && RARRAY_LEN(trace) > 0) {
|
51
|
+
printf("we got an exception: %s:%d\n", StringValueCStr(ret), RARRAY_LEN(trace));
|
52
|
+
VALUE sep = rb_str_new_cstr("\n");
|
53
|
+
VALUE trace_lines = rb_ary_join(trace, sep);
|
54
|
+
if (RB_TYPE_P(trace_lines, T_STRING)) {
|
55
|
+
printf("%s\n", StringValueCStr(trace_lines));
|
56
|
+
} else {
|
57
|
+
printf("trace is not a string??\n");
|
58
|
+
}
|
59
|
+
} else {
|
60
|
+
printf("we got an exception: %s\nno stack available\n", StringValueCStr(ret));
|
61
|
+
}
|
62
|
+
*/
|
63
|
+
rb_hash_aset(did_raise, rb_easy_hkey("error"), exception);
|
64
|
+
return exception;
|
48
65
|
}
|
49
66
|
|
50
67
|
void curl_multi_free(ruby_curl_multi *rbcm) {
|
@@ -64,7 +81,7 @@ static void ruby_curl_multi_init(ruby_curl_multi *rbcm) {
|
|
64
81
|
|
65
82
|
/*
|
66
83
|
* call-seq:
|
67
|
-
* Curl::Multi.new =>
|
84
|
+
* Curl::Multi.new => #<Curl::Easy...>
|
68
85
|
*
|
69
86
|
* Create a new Curl::Multi instance
|
70
87
|
*/
|
@@ -132,7 +149,7 @@ VALUE ruby_curl_multi_get_autoclose(VALUE klass) {
|
|
132
149
|
|
133
150
|
/*
|
134
151
|
* call-seq:
|
135
|
-
* multi.requests => [
|
152
|
+
* multi.requests => [#<Curl::Easy...>, ...]
|
136
153
|
*
|
137
154
|
* Returns an array containing all the active requests on this Curl::Multi object.
|
138
155
|
*/
|
@@ -274,7 +291,7 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
274
291
|
long response_code = -1;
|
275
292
|
VALUE easy;
|
276
293
|
ruby_curl_easy *rbce = NULL;
|
277
|
-
VALUE callargs
|
294
|
+
VALUE callargs;
|
278
295
|
|
279
296
|
CURLcode ecode = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (char**)&easy);
|
280
297
|
|
@@ -295,55 +312,62 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
295
312
|
raise_curl_easy_error_exception(ecode);
|
296
313
|
}
|
297
314
|
|
315
|
+
VALUE did_raise = rb_hash_new();
|
316
|
+
|
298
317
|
if (!rb_easy_nil("complete_proc")) {
|
299
318
|
callargs = rb_ary_new3(2, rb_easy_get("complete_proc"), easy);
|
300
319
|
rbce->callback_active = 1;
|
301
|
-
|
320
|
+
rb_rescue(call_status_handler1, callargs, callback_exception, did_raise);
|
302
321
|
rbce->callback_active = 0;
|
303
|
-
|
322
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
304
323
|
}
|
305
324
|
|
325
|
+
#ifdef HAVE_CURLINFO_RESPONSE_CODE
|
306
326
|
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &response_code);
|
327
|
+
#else
|
328
|
+
// old libcurl
|
329
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CODE, &response_code);
|
330
|
+
#endif
|
331
|
+
long redirect_count;
|
332
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &redirect_count);
|
307
333
|
|
308
334
|
if (result != 0) {
|
309
335
|
if (!rb_easy_nil("failure_proc")) {
|
310
336
|
callargs = rb_ary_new3(3, rb_easy_get("failure_proc"), easy, rb_curl_easy_error(result));
|
311
337
|
rbce->callback_active = 1;
|
312
|
-
|
338
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
313
339
|
rbce->callback_active = 0;
|
314
|
-
|
340
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
315
341
|
}
|
316
|
-
}
|
317
|
-
else if (!rb_easy_nil("success_proc") &&
|
342
|
+
} else if (!rb_easy_nil("success_proc") &&
|
318
343
|
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
319
344
|
/* NOTE: we allow response_code == 0, in the case of non http requests e.g. reading from disk */
|
320
345
|
callargs = rb_ary_new3(2, rb_easy_get("success_proc"), easy);
|
321
346
|
rbce->callback_active = 1;
|
322
|
-
|
347
|
+
rb_rescue(call_status_handler1, callargs, callback_exception, did_raise);
|
323
348
|
rbce->callback_active = 0;
|
324
|
-
|
325
|
-
|
326
|
-
else if (!rb_easy_nil("redirect_proc") &&
|
327
|
-
(response_code >= 300 && response_code < 400)) {
|
349
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
350
|
+
|
351
|
+
} else if (!rb_easy_nil("redirect_proc") && ((response_code >= 300 && response_code < 400) || redirect_count > 0) ) {
|
328
352
|
rbce->callback_active = 1;
|
329
353
|
callargs = rb_ary_new3(3, rb_easy_get("redirect_proc"), easy, rb_curl_easy_error(result));
|
330
354
|
rbce->callback_active = 0;
|
331
|
-
|
332
|
-
|
333
|
-
else if (!rb_easy_nil("missing_proc") &&
|
355
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
356
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
357
|
+
} else if (!rb_easy_nil("missing_proc") &&
|
334
358
|
(response_code >= 400 && response_code < 500)) {
|
335
359
|
rbce->callback_active = 1;
|
336
360
|
callargs = rb_ary_new3(3, rb_easy_get("missing_proc"), easy, rb_curl_easy_error(result));
|
337
361
|
rbce->callback_active = 0;
|
338
|
-
|
339
|
-
|
340
|
-
else if (!rb_easy_nil("failure_proc") &&
|
362
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
363
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
364
|
+
} else if (!rb_easy_nil("failure_proc") &&
|
341
365
|
(response_code >= 500 && response_code <= 999)) {
|
342
366
|
callargs = rb_ary_new3(3, rb_easy_get("failure_proc"), easy, rb_curl_easy_error(result));
|
343
367
|
rbce->callback_active = 1;
|
344
|
-
|
368
|
+
rb_rescue(call_status_handler2, callargs, callback_exception, did_raise);
|
345
369
|
rbce->callback_active = 0;
|
346
|
-
|
370
|
+
CURB_CHECK_RB_CALLBACK_RAISE(did_raise);
|
347
371
|
}
|
348
372
|
|
349
373
|
}
|
@@ -627,6 +651,8 @@ void init_curb_multi() {
|
|
627
651
|
idCall = rb_intern("call");
|
628
652
|
cCurlMulti = rb_define_class_under(mCurl, "Multi", rb_cObject);
|
629
653
|
|
654
|
+
rb_undef_alloc_func(cCurlMulti);
|
655
|
+
|
630
656
|
/* Class methods */
|
631
657
|
rb_define_singleton_method(cCurlMulti, "new", ruby_curl_multi_new, 0);
|
632
658
|
rb_define_singleton_method(cCurlMulti, "default_timeout=", ruby_curl_multi_set_default_timeout, 1);
|
data/ext/curb_postfield.c
CHANGED
@@ -195,9 +195,9 @@ void curl_postfield_free(ruby_curl_postfield *rbcpf) {
|
|
195
195
|
|
196
196
|
/*
|
197
197
|
* call-seq:
|
198
|
-
* Curl::PostField.content(name, content) =>
|
199
|
-
* Curl::PostField.content(name, content, content_type = nil) =>
|
200
|
-
* Curl::PostField.content(name, content_type = nil) { |field| ... } =>
|
198
|
+
* Curl::PostField.content(name, content) => #<Curl::PostField...>
|
199
|
+
* Curl::PostField.content(name, content, content_type = nil) => #<Curl::PostField...>
|
200
|
+
* Curl::PostField.content(name, content_type = nil) { |field| ... } => #<Curl::PostField...>
|
201
201
|
*
|
202
202
|
* Create a new Curl::PostField, supplying the field name, content,
|
203
203
|
* and, optionally, Content-type (curl will attempt to determine this if
|
@@ -241,9 +241,9 @@ static VALUE ruby_curl_postfield_new_content(int argc, VALUE *argv, VALUE klass)
|
|
241
241
|
|
242
242
|
/*
|
243
243
|
* call-seq:
|
244
|
-
* Curl::PostField.file(name, local_file_name) =>
|
245
|
-
* Curl::PostField.file(name, local_file_name, remote_file_name = local_file_name) =>
|
246
|
-
* Curl::PostField.file(name, remote_file_name) { |field| ... } =>
|
244
|
+
* Curl::PostField.file(name, local_file_name) => #<Curl::PostField...>
|
245
|
+
* Curl::PostField.file(name, local_file_name, remote_file_name = local_file_name) => #<Curl::PostField...>
|
246
|
+
* Curl::PostField.file(name, remote_file_name) { |field| ... } => #<Curl::PostField...>
|
247
247
|
*
|
248
248
|
* Create a new Curl::PostField for a file upload field, supplying the local filename
|
249
249
|
* to read from, and optionally the remote filename (defaults to the local name).
|
@@ -399,7 +399,7 @@ static VALUE ruby_curl_postfield_remote_file_get(VALUE self) {
|
|
399
399
|
|
400
400
|
/*
|
401
401
|
* call-seq:
|
402
|
-
* field.set_content_proc { |field| ... } =>
|
402
|
+
* field.set_content_proc { |field| ... } => <old proc>
|
403
403
|
*
|
404
404
|
* Set a content proc for this field. This proc will be called during the
|
405
405
|
* perform to supply the content for this field, overriding any setting
|
@@ -498,6 +498,8 @@ void init_curb_postfield() {
|
|
498
498
|
|
499
499
|
cCurlPostField = rb_define_class_under(mCurl, "PostField", rb_cObject);
|
500
500
|
|
501
|
+
rb_undef_alloc_func(cCurlPostField);
|
502
|
+
|
501
503
|
/* Class methods */
|
502
504
|
rb_define_singleton_method(cCurlPostField, "content", ruby_curl_postfield_new_content, -1);
|
503
505
|
rb_define_singleton_method(cCurlPostField, "file", ruby_curl_postfield_new_file, -1);
|
data/ext/curb_upload.c
CHANGED
@@ -72,6 +72,7 @@ VALUE ruby_curl_upload_offset_get(VALUE self) {
|
|
72
72
|
/* =================== INIT LIB =====================*/
|
73
73
|
void init_curb_upload() {
|
74
74
|
cCurlUpload = rb_define_class_under(mCurl, "Upload", rb_cObject);
|
75
|
+
rb_undef_alloc_func(cCurlUpload);
|
75
76
|
rb_define_singleton_method(cCurlUpload, "new", ruby_curl_upload_new, 0);
|
76
77
|
rb_define_method(cCurlUpload, "stream=", ruby_curl_upload_stream_set, 1);
|
77
78
|
rb_define_method(cCurlUpload, "stream", ruby_curl_upload_stream_get, 0);
|
data/ext/extconf.rb
CHANGED
@@ -18,6 +18,8 @@ elsif !have_library('curl') or !have_header('curl/curl.h')
|
|
18
18
|
fail <<-EOM
|
19
19
|
Can't find libcurl or curl/curl.h
|
20
20
|
|
21
|
+
Make sure development libs (ie libcurl4-openssl-dev) are installed on the system.
|
22
|
+
|
21
23
|
Try passing --with-curl-dir or --with-curl-lib and --with-curl-include
|
22
24
|
options to extconf.
|
23
25
|
EOM
|
@@ -59,6 +61,9 @@ def have_constant(name)
|
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
64
|
+
have_constant "curlopt_tcp_keepalive"
|
65
|
+
have_constant "curlopt_tcp_keepidle"
|
66
|
+
have_constant "curlopt_tcp_keepintvl"
|
62
67
|
have_constant "curlinfo_appconnect_time"
|
63
68
|
have_constant "curlinfo_redirect_time"
|
64
69
|
have_constant "curlinfo_response_code"
|
@@ -153,6 +158,8 @@ have_func("curl_multi_timeout")
|
|
153
158
|
have_func("curl_multi_fdset")
|
154
159
|
have_func("curl_multi_perform")
|
155
160
|
|
161
|
+
have_constant "curlopt_haproxyprotocol"
|
162
|
+
|
156
163
|
# constants
|
157
164
|
have_constant "curlopt_interleavefunction"
|
158
165
|
have_constant "curlopt_interleavedata"
|
@@ -336,6 +343,9 @@ have_constant :CURL_SSLVERSION_TLSv1_0
|
|
336
343
|
have_constant :CURL_SSLVERSION_TLSv1_1
|
337
344
|
have_constant :CURL_SSLVERSION_TLSv1_2
|
338
345
|
|
346
|
+
# Added in 7.52.0
|
347
|
+
have_constant :CURL_SSLVERSION_TLSv1_3
|
348
|
+
|
339
349
|
have_constant "curlopt_ssl_verifypeer"
|
340
350
|
have_constant "curlopt_cainfo"
|
341
351
|
have_constant "curlopt_issuercert"
|
@@ -395,6 +405,39 @@ have_constant "curlopt_path_as_is"
|
|
395
405
|
# added in 7.43.0
|
396
406
|
have_constant "curlopt_pipewait"
|
397
407
|
|
408
|
+
have_constant "curlopt_proxy_ssl_verifyhost"
|
409
|
+
|
410
|
+
# protocol constants
|
411
|
+
have_constant "curlproto_all"
|
412
|
+
have_constant "curlproto_dict"
|
413
|
+
have_constant "curlproto_file"
|
414
|
+
have_constant "curlproto_ftp"
|
415
|
+
have_constant "curlproto_ftps"
|
416
|
+
have_constant "curlproto_gopher"
|
417
|
+
have_constant "curlproto_http"
|
418
|
+
have_constant "curlproto_https"
|
419
|
+
have_constant "curlproto_imap"
|
420
|
+
have_constant "curlproto_imaps"
|
421
|
+
have_constant "curlproto_ldap"
|
422
|
+
have_constant "curlproto_ldaps"
|
423
|
+
have_constant "curlproto_pop3"
|
424
|
+
have_constant "curlproto_pop3s"
|
425
|
+
have_constant "curlproto_rtmp"
|
426
|
+
have_constant "curlproto_rtmpe"
|
427
|
+
have_constant "curlproto_rtmps"
|
428
|
+
have_constant "curlproto_rtmpt"
|
429
|
+
have_constant "curlproto_rtmpte"
|
430
|
+
have_constant "curlproto_rtmpts"
|
431
|
+
have_constant "curlproto_rtsp"
|
432
|
+
have_constant "curlproto_scp"
|
433
|
+
have_constant "curlproto_sftp"
|
434
|
+
have_constant "curlproto_smb"
|
435
|
+
have_constant "curlproto_smbs"
|
436
|
+
have_constant "curlproto_smtp"
|
437
|
+
have_constant "curlproto_smtps"
|
438
|
+
have_constant "curlproto_telnet"
|
439
|
+
have_constant "curlproto_tftp"
|
440
|
+
|
398
441
|
if try_compile('int main() { return 0; }','-Wall')
|
399
442
|
$CFLAGS << ' -Wall'
|
400
443
|
end
|
@@ -422,6 +465,8 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
|
|
422
465
|
|
423
466
|
have_func('rb_thread_blocking_region')
|
424
467
|
have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
468
|
+
have_header('ruby/io.h')
|
469
|
+
have_func('rb_io_stdio_file')
|
425
470
|
|
426
471
|
create_header('curb_config.h')
|
427
472
|
create_makefile('curb_core')
|
data/lib/curb.rb
CHANGED
data/lib/curl/easy.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Curl
|
2
3
|
class Easy
|
3
4
|
|
@@ -20,7 +21,7 @@ module Curl
|
|
20
21
|
#
|
21
22
|
def status
|
22
23
|
# Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP (Opt:)Reason-Phrase CRLF'
|
23
|
-
statuses = self.header_str.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map{
|
24
|
+
statuses = self.header_str.to_s.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map {|match| match[1] }
|
24
25
|
statuses.last.strip if statuses.length > 0
|
25
26
|
end
|
26
27
|
|
@@ -68,9 +69,15 @@ module Curl
|
|
68
69
|
ret = self.multi.perform
|
69
70
|
self.multi.remove self
|
70
71
|
|
72
|
+
if Curl::Multi.autoclose
|
73
|
+
self.multi.close
|
74
|
+
self.multi = nil
|
75
|
+
end
|
76
|
+
|
71
77
|
if self.last_result != 0 && self.on_failure.nil?
|
72
|
-
|
73
|
-
|
78
|
+
(err_class, err_summary) = Curl::Easy.error(self.last_result)
|
79
|
+
err_detail = self.last_error
|
80
|
+
raise err_class.new([err_summary, err_detail].compact.join(": "))
|
74
81
|
end
|
75
82
|
|
76
83
|
ret
|
@@ -314,7 +321,7 @@ module Curl
|
|
314
321
|
|
315
322
|
#
|
316
323
|
# call-seq:
|
317
|
-
# Curl::Easy.perform(url) { |easy| ... } =>
|
324
|
+
# Curl::Easy.perform(url) { |easy| ... } => #<Curl::Easy...>
|
318
325
|
#
|
319
326
|
# Convenience method that creates a new Curl::Easy instance with
|
320
327
|
# the specified URL and calls the general +perform+ method, before returning
|
@@ -332,7 +339,7 @@ module Curl
|
|
332
339
|
|
333
340
|
#
|
334
341
|
# call-seq:
|
335
|
-
# Curl::Easy.http_get(url) { |easy| ... } =>
|
342
|
+
# Curl::Easy.http_get(url) { |easy| ... } => #<Curl::Easy...>
|
336
343
|
#
|
337
344
|
# Convenience method that creates a new Curl::Easy instance with
|
338
345
|
# the specified URL and calls +http_get+, before returning the new instance.
|
@@ -349,7 +356,7 @@ module Curl
|
|
349
356
|
|
350
357
|
#
|
351
358
|
# call-seq:
|
352
|
-
# Curl::Easy.http_head(url) { |easy| ... } =>
|
359
|
+
# Curl::Easy.http_head(url) { |easy| ... } => #<Curl::Easy...>
|
353
360
|
#
|
354
361
|
# Convenience method that creates a new Curl::Easy instance with
|
355
362
|
# the specified URL and calls +http_head+, before returning the new instance.
|
@@ -403,7 +410,7 @@ module Curl
|
|
403
410
|
|
404
411
|
#
|
405
412
|
# call-seq:
|
406
|
-
# Curl::Easy.http_delete(url) { |easy| ... } =>
|
413
|
+
# Curl::Easy.http_delete(url) { |easy| ... } => #<Curl::Easy...>
|
407
414
|
#
|
408
415
|
# Convenience method that creates a new Curl::Easy instance with
|
409
416
|
# the specified URL and calls +http_delete+, before returning the new instance.
|
data/lib/curl/multi.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Curl
|
2
3
|
class Multi
|
4
|
+
class DownloadError < RuntimeError
|
5
|
+
attr_accessor :errors
|
6
|
+
end
|
3
7
|
class << self
|
4
8
|
# call-seq:
|
5
9
|
# Curl::Multi.get(['url1','url2','url3','url4','url5'], :follow_location => true) do|easy|
|
@@ -143,7 +147,7 @@ module Curl
|
|
143
147
|
|
144
148
|
max_connects.times do
|
145
149
|
conf = urls_with_config.pop
|
146
|
-
add_free_handle.call
|
150
|
+
add_free_handle.call(conf, nil) if conf
|
147
151
|
break if urls_with_config.empty?
|
148
152
|
end
|
149
153
|
|
@@ -152,7 +156,7 @@ module Curl
|
|
152
156
|
if urls_with_config.size > 0 && free_handles.size > 0
|
153
157
|
easy = free_handles.pop
|
154
158
|
conf = urls_with_config.pop
|
155
|
-
add_free_handle.call
|
159
|
+
add_free_handle.call(conf, easy) if conf
|
156
160
|
end
|
157
161
|
end
|
158
162
|
|
@@ -240,7 +244,11 @@ module Curl
|
|
240
244
|
errors << e
|
241
245
|
end
|
242
246
|
}
|
243
|
-
|
247
|
+
if errors.any?
|
248
|
+
de = Curl::Multi::DownloadError.new
|
249
|
+
de.errors = errors
|
250
|
+
raise de
|
251
|
+
end
|
244
252
|
end
|
245
253
|
end
|
246
254
|
|
data/lib/curl.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'curb_core'
|
2
3
|
require 'curl/easy'
|
3
4
|
require 'curl/multi'
|
@@ -8,12 +9,20 @@ require 'cgi'
|
|
8
9
|
module Curl
|
9
10
|
|
10
11
|
def self.http(verb, url, post_body=nil, put_data=nil, &block)
|
11
|
-
|
12
|
-
|
12
|
+
if Thread.current[:curb_curl_yielding]
|
13
|
+
handle = Curl::Easy.new # we can't reuse this
|
14
|
+
else
|
15
|
+
handle = Thread.current[:curb_curl] ||= Curl::Easy.new
|
16
|
+
handle.reset
|
17
|
+
end
|
13
18
|
handle.url = url
|
14
19
|
handle.post_body = post_body if post_body
|
15
20
|
handle.put_data = put_data if put_data
|
16
|
-
|
21
|
+
if block_given?
|
22
|
+
Thread.current[:curb_curl_yielding] = true
|
23
|
+
yield handle
|
24
|
+
Thread.current[:curb_curl_yielding] = false
|
25
|
+
end
|
17
26
|
handle.http(verb)
|
18
27
|
handle
|
19
28
|
end
|
data/tests/bug_crash_on_debug.rb
CHANGED
@@ -1,37 +1,23 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
2
|
|
3
|
-
require 'webrick'
|
4
|
-
class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
|
5
|
-
class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
|
6
|
-
|
7
|
-
require 'curl'
|
8
|
-
|
9
3
|
class BugCrashOnDebug < Test::Unit::TestCase
|
4
|
+
include BugTestServerSetupTeardown
|
10
5
|
|
11
6
|
def test_on_debug
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
c.on_debug do|x|
|
24
|
-
puts x.inspect
|
25
|
-
raise "error" # this will get swallowed
|
7
|
+
c = Curl::Easy.new("http://127.0.0.1:#{@port}/test")
|
8
|
+
did_raise = false
|
9
|
+
did_call = false
|
10
|
+
begin
|
11
|
+
c.on_success do|x|
|
12
|
+
did_call = true
|
13
|
+
raise "error" # this will get swallowed
|
14
|
+
end
|
15
|
+
c.perform
|
16
|
+
rescue => e
|
17
|
+
did_raise = true
|
26
18
|
end
|
27
|
-
|
28
|
-
|
29
|
-
ensure
|
30
|
-
puts 'd'
|
31
|
-
server.shutdown
|
32
|
-
puts 'e'
|
33
|
-
puts thread.exit
|
34
|
-
puts 'f'
|
19
|
+
assert did_raise
|
20
|
+
assert did_call
|
35
21
|
end
|
36
22
|
|
37
23
|
end
|
@@ -1,22 +1,10 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
-
require 'webrick'
|
3
|
-
class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
|
4
|
-
class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
|
5
2
|
|
6
3
|
class BugCrashOnDebug < Test::Unit::TestCase
|
7
|
-
|
8
|
-
def test_on_progress_raise
|
9
|
-
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
10
|
-
server.mount_proc("/test") do|req,res|
|
11
|
-
res.body = "hi"
|
12
|
-
res['Content-Type'] = "text/html"
|
13
|
-
end
|
4
|
+
include BugTestServerSetupTeardown
|
14
5
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
c = Curl::Easy.new('http://127.0.0.1:9999/test')
|
6
|
+
def test_on_progress_raise
|
7
|
+
c = Curl::Easy.new("http://127.0.0.1:#{@port}/test")
|
20
8
|
c.on_progress do|x|
|
21
9
|
raise "error"
|
22
10
|
end
|
@@ -27,21 +15,9 @@ class BugCrashOnDebug < Test::Unit::TestCase
|
|
27
15
|
rescue => e
|
28
16
|
assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
|
29
17
|
c.close
|
30
|
-
ensure
|
31
|
-
server.shutdown
|
32
18
|
end
|
33
19
|
|
34
20
|
def test_on_progress_abort
|
35
|
-
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
36
|
-
server.mount_proc("/test") do|req,res|
|
37
|
-
res.body = "hi"
|
38
|
-
res['Content-Type'] = "text/html"
|
39
|
-
end
|
40
|
-
|
41
|
-
thread = Thread.new(server) do|srv|
|
42
|
-
srv.start
|
43
|
-
end
|
44
|
-
|
45
21
|
# see: https://github.com/taf2/curb/issues/192,
|
46
22
|
# to pass:
|
47
23
|
#
|
@@ -54,20 +30,20 @@ class BugCrashOnDebug < Test::Unit::TestCase
|
|
54
30
|
#
|
55
31
|
# notice no return keyword
|
56
32
|
#
|
57
|
-
c = Curl::Easy.new(
|
33
|
+
c = Curl::Easy.new("http://127.0.0.1:#{@port}/test")
|
34
|
+
did_progress = false
|
58
35
|
c.on_progress do|x|
|
59
|
-
|
36
|
+
did_progress = true
|
60
37
|
return false
|
61
38
|
end
|
62
39
|
c.perform
|
40
|
+
assert did_progress
|
63
41
|
|
64
42
|
assert false, "should not reach this point"
|
65
43
|
|
66
44
|
rescue => e
|
67
45
|
assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
|
68
46
|
c.close
|
69
|
-
ensure
|
70
|
-
server.shutdown
|
71
47
|
end
|
72
48
|
|
73
49
|
end
|
@@ -1,21 +1,19 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
-
require 'webrick'
|
3
|
-
class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
|
4
|
-
class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
|
5
2
|
|
6
3
|
class BugTestInstancePostDiffersFromClassPost < Test::Unit::TestCase
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
include BugTestServerSetupTeardown
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@port = 9999
|
8
|
+
@response_proc = lambda do|res|
|
10
9
|
sleep 0.5
|
11
10
|
res.body = "hi"
|
12
11
|
res['Content-Type'] = "text/html"
|
13
12
|
end
|
13
|
+
super
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
srv.start
|
17
|
-
end
|
18
|
-
|
16
|
+
def test_bug
|
19
17
|
threads = []
|
20
18
|
timer = Time.now
|
21
19
|
|
@@ -45,8 +43,5 @@ class BugTestInstancePostDiffersFromClassPost < Test::Unit::TestCase
|
|
45
43
|
puts "requested in #{single_time}"
|
46
44
|
|
47
45
|
assert single_time > multi_time
|
48
|
-
|
49
|
-
server.shutdown
|
50
|
-
thread.join
|
51
46
|
end
|
52
47
|
end
|
@@ -22,26 +22,15 @@ end
|
|
22
22
|
Any insight you care to share would be helpful. Thanks.
|
23
23
|
=end
|
24
24
|
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
25
|
-
require 'webrick'
|
26
|
-
class ::WEBrick::HTTPServer ; def access_log(config, req, res) ; end ; end
|
27
|
-
class ::WEBrick::BasicLog ; def log(level, data) ; end ; end
|
28
25
|
|
29
26
|
class BugCurbEasyPostWithStringNoContentLengthHeader < Test::Unit::TestCase
|
30
|
-
|
31
|
-
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
32
|
-
server.mount_proc("/test") do|req,res|
|
33
|
-
assert_equal '15', req['Content-Length']
|
34
|
-
res.body = "hi"
|
35
|
-
res['Content-Type'] = "text/html"
|
36
|
-
end
|
27
|
+
include BugTestServerSetupTeardown
|
37
28
|
|
38
|
-
|
39
|
-
srv.start
|
40
|
-
end
|
29
|
+
def test_bug_workaround
|
41
30
|
params = {:cat => "hat", :foo => "bar"}
|
42
31
|
|
43
32
|
post_body = params.map{|f,k| "#{Curl::Easy.new.escape(f)}=#{Curl::Easy.new.escape(k)}"}.join('&')
|
44
|
-
c = Curl::Easy.http_post("http://127.0.0.1
|
33
|
+
c = Curl::Easy.http_post("http://127.0.0.1:#{@port}/test",post_body) do |curl|
|
45
34
|
curl.headers["User-Agent"] = "Curl/Ruby"
|
46
35
|
curl.headers["X-Tender-Auth"] = "A Token"
|
47
36
|
curl.headers["Accept"] = "application/vnd.tender-v1+json"
|
@@ -50,23 +39,12 @@ class BugCurbEasyPostWithStringNoContentLengthHeader < Test::Unit::TestCase
|
|
50
39
|
curl.enable_cookies = true
|
51
40
|
end
|
52
41
|
|
53
|
-
server.shutdown
|
54
|
-
thread.join
|
55
42
|
end
|
56
|
-
def test_bug
|
57
|
-
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
58
|
-
server.mount_proc("/test") do|req,res|
|
59
|
-
assert_equal '15', req['Content-Length']
|
60
|
-
res.body = "hi"
|
61
|
-
res['Content-Type'] = "text/html"
|
62
|
-
end
|
63
43
|
|
64
|
-
|
65
|
-
srv.start
|
66
|
-
end
|
44
|
+
def test_bug
|
67
45
|
params = {:cat => "hat", :foo => "bar"}
|
68
46
|
|
69
|
-
c = Curl::Easy.http_post("http://127.0.0.1
|
47
|
+
c = Curl::Easy.http_post("http://127.0.0.1:#{@port}/test") do |curl|
|
70
48
|
curl.headers["User-Agent"] = "Curl/Ruby"
|
71
49
|
curl.headers["X-Tender-Auth"] = "A Token"
|
72
50
|
curl.headers["Accept"] = "application/vnd.tender-v1+json"
|
@@ -76,8 +54,6 @@ class BugCurbEasyPostWithStringNoContentLengthHeader < Test::Unit::TestCase
|
|
76
54
|
curl.follow_location = true
|
77
55
|
curl.enable_cookies = true
|
78
56
|
end
|
79
|
-
|
80
|
-
server.shutdown
|
81
|
-
thread.join
|
82
57
|
end
|
58
|
+
|
83
59
|
end
|