curb 0.9.3 → 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 +5 -5
- data/README.markdown +90 -22
- data/Rakefile +35 -20
- data/ext/banned.h +32 -0
- data/ext/curb.c +190 -14
- data/ext/curb.h +18 -5
- data/ext/curb_easy.c +514 -98
- data/ext/curb_easy.h +7 -0
- data/ext/curb_errors.c +86 -0
- data/ext/curb_macros.h +12 -0
- data/ext/curb_multi.c +178 -229
- data/ext/curb_multi.h +0 -1
- data/ext/curb_postfield.c +9 -7
- data/ext/curb_upload.c +1 -0
- data/ext/extconf.rb +76 -6
- data/lib/curb.rb +1 -0
- data/lib/curl/easy.rb +16 -9
- data/lib/curl/multi.rb +60 -14
- data/lib/curl.rb +20 -12
- 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 +122 -13
- data/tests/tc_curl.rb +31 -1
- data/tests/tc_curl_download.rb +3 -3
- data/tests/tc_curl_easy.rb +167 -46
- data/tests/tc_curl_easy_resolve.rb +16 -0
- data/tests/tc_curl_maxfilesize.rb +12 -0
- data/tests/tc_curl_multi.rb +161 -18
- data/tests/tc_curl_postfield.rb +29 -29
- data/tests/tc_curl_protocols.rb +37 -0
- data/tests/timeout.rb +21 -5
- metadata +20 -8
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"
|
@@ -66,6 +71,7 @@ have_constant "curlinfo_filetime"
|
|
66
71
|
have_constant "curlinfo_redirect_count"
|
67
72
|
have_constant "curlinfo_os_errno"
|
68
73
|
have_constant "curlinfo_num_connects"
|
74
|
+
have_constant "curlinfo_cookielist"
|
69
75
|
have_constant "curlinfo_ftp_entry_path"
|
70
76
|
have_constant "curl_version_ssl"
|
71
77
|
have_constant "curl_version_libz"
|
@@ -83,6 +89,7 @@ have_constant "curlproxy_http"
|
|
83
89
|
have_constant "curlproxy_socks4"
|
84
90
|
have_constant "curlproxy_socks4a"
|
85
91
|
have_constant "curlproxy_socks5"
|
92
|
+
have_constant "curlproxy_socks5_hostname"
|
86
93
|
have_constant "curlauth_basic"
|
87
94
|
have_constant "curlauth_digest"
|
88
95
|
have_constant "curlauth_gssnegotiate"
|
@@ -101,6 +108,12 @@ have_constant "curle_send_fail_rewind"
|
|
101
108
|
have_constant "curle_ssl_engine_initfailed"
|
102
109
|
have_constant "curle_login_denied"
|
103
110
|
|
111
|
+
# older than 7.10.0
|
112
|
+
have_constant "curlopt_nosignal"
|
113
|
+
|
114
|
+
# older than 7.16.0
|
115
|
+
have_constant "curlmopt_pipelining"
|
116
|
+
|
104
117
|
# older than 7.16.3
|
105
118
|
have_constant "curlmopt_maxconnects"
|
106
119
|
|
@@ -145,6 +158,8 @@ have_func("curl_multi_timeout")
|
|
145
158
|
have_func("curl_multi_fdset")
|
146
159
|
have_func("curl_multi_perform")
|
147
160
|
|
161
|
+
have_constant "curlopt_haproxyprotocol"
|
162
|
+
|
148
163
|
# constants
|
149
164
|
have_constant "curlopt_interleavefunction"
|
150
165
|
have_constant "curlopt_interleavedata"
|
@@ -209,6 +224,7 @@ have_constant "curlopt_httppost"
|
|
209
224
|
have_constant "curlopt_referer"
|
210
225
|
have_constant "curlopt_useragent"
|
211
226
|
have_constant "curlopt_httpheader"
|
227
|
+
have_constant "curlopt_proxyheader"
|
212
228
|
have_constant "curlopt_http200aliases"
|
213
229
|
have_constant "curlopt_cookie"
|
214
230
|
have_constant "curlopt_cookiefile"
|
@@ -318,14 +334,17 @@ have_constant "curlopt_sslengine"
|
|
318
334
|
have_constant "curlopt_sslengine_default"
|
319
335
|
have_constant "curlopt_sslversion"
|
320
336
|
have_constant "curl_sslversion_default"
|
321
|
-
have_constant
|
322
|
-
have_constant
|
323
|
-
have_constant
|
337
|
+
have_constant :CURL_SSLVERSION_TLSv1
|
338
|
+
have_constant :CURL_SSLVERSION_SSLv2
|
339
|
+
have_constant :CURL_SSLVERSION_SSLv3
|
324
340
|
|
325
341
|
# Added in 7.34.0
|
326
|
-
have_constant
|
327
|
-
have_constant
|
328
|
-
have_constant
|
342
|
+
have_constant :CURL_SSLVERSION_TLSv1_0
|
343
|
+
have_constant :CURL_SSLVERSION_TLSv1_1
|
344
|
+
have_constant :CURL_SSLVERSION_TLSv1_2
|
345
|
+
|
346
|
+
# Added in 7.52.0
|
347
|
+
have_constant :CURL_SSLVERSION_TLSv1_3
|
329
348
|
|
330
349
|
have_constant "curlopt_ssl_verifypeer"
|
331
350
|
have_constant "curlopt_cainfo"
|
@@ -360,6 +379,16 @@ have_constant "curle_not_built_in"
|
|
360
379
|
|
361
380
|
have_constant "curle_obsolete" # removed in 7.24 ?
|
362
381
|
|
382
|
+
have_constant "curle_ftp_pret_failed"
|
383
|
+
have_constant "curle_rtsp_cseq_error"
|
384
|
+
have_constant "curle_rtsp_session_error"
|
385
|
+
have_constant "curle_ftp_bad_file_list"
|
386
|
+
have_constant "curle_chunk_failed"
|
387
|
+
have_constant "curle_no_connection_available"
|
388
|
+
have_constant "curle_ssl_pinnedpubkeynotmatch"
|
389
|
+
have_constant "curle_ssl_invalidcertstatus"
|
390
|
+
have_constant "curle_http2_stream"
|
391
|
+
|
363
392
|
# gssapi/spnego delegation related constants
|
364
393
|
have_constant "curlopt_gssapi_delegation"
|
365
394
|
have_constant "curlgssapi_delegation_policy_flag"
|
@@ -370,6 +399,45 @@ have_constant "CURLM_ADDED_ALREADY"
|
|
370
399
|
# added in 7.40.0
|
371
400
|
have_constant "curlopt_unix_socket_path"
|
372
401
|
|
402
|
+
# added in 7.42.0
|
403
|
+
have_constant "curlopt_path_as_is"
|
404
|
+
|
405
|
+
# added in 7.43.0
|
406
|
+
have_constant "curlopt_pipewait"
|
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
|
+
|
373
441
|
if try_compile('int main() { return 0; }','-Wall')
|
374
442
|
$CFLAGS << ' -Wall'
|
375
443
|
end
|
@@ -397,6 +465,8 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
|
|
397
465
|
|
398
466
|
have_func('rb_thread_blocking_region')
|
399
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')
|
400
470
|
|
401
471
|
create_header('curb_config.h')
|
402
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
|
|
@@ -19,9 +20,9 @@ module Curl
|
|
19
20
|
# easy.status => String
|
20
21
|
#
|
21
22
|
def status
|
22
|
-
# Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF'
|
23
|
-
statuses = self.header_str.scan(/HTTP\/\d\.\d
|
24
|
-
statuses.last.strip
|
23
|
+
# Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP (Opt:)Reason-Phrase CRLF'
|
24
|
+
statuses = self.header_str.to_s.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map {|match| match[1] }
|
25
|
+
statuses.last.strip if statuses.length > 0
|
25
26
|
end
|
26
27
|
|
27
28
|
#
|
@@ -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,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Curl
|
2
|
-
|
3
3
|
class Multi
|
4
|
+
class DownloadError < RuntimeError
|
5
|
+
attr_accessor :errors
|
6
|
+
end
|
4
7
|
class << self
|
5
8
|
# call-seq:
|
6
9
|
# Curl::Multi.get(['url1','url2','url3','url4','url5'], :follow_location => true) do|easy|
|
7
10
|
# easy
|
8
11
|
# end
|
9
|
-
#
|
12
|
+
#
|
10
13
|
# Blocking call to fetch multiple url's in parallel.
|
11
14
|
def get(urls, easy_options={}, multi_options={}, &blk)
|
12
15
|
url_confs = []
|
@@ -25,10 +28,10 @@ module Curl
|
|
25
28
|
# {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
|
26
29
|
# easy_handle_on_request_complete
|
27
30
|
# end
|
28
|
-
#
|
31
|
+
#
|
29
32
|
# 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
|
33
|
+
#
|
34
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
32
35
|
# easy_options: are a set of common options to set on all easy handles
|
33
36
|
# multi_options: options to set on the Curl::Multi handle
|
34
37
|
#
|
@@ -49,10 +52,10 @@ module Curl
|
|
49
52
|
# {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
|
50
53
|
# easy_handle_on_request_complete
|
51
54
|
# end
|
52
|
-
#
|
55
|
+
#
|
53
56
|
# 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
|
57
|
+
#
|
58
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
56
59
|
# easy_options: are a set of common options to set on all easy handles
|
57
60
|
# multi_options: options to set on the Curl::Multi handle
|
58
61
|
#
|
@@ -79,7 +82,7 @@ module Curl
|
|
79
82
|
# Blocking call to issue multiple HTTP requests with varying verb's.
|
80
83
|
#
|
81
84
|
# 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
|
85
|
+
# multi_options: options for the multi handle
|
83
86
|
# blk: a callback, that yeilds when a handle is completed
|
84
87
|
#
|
85
88
|
def http(urls_with_config, multi_options={}, &blk)
|
@@ -128,7 +131,7 @@ module Curl
|
|
128
131
|
|
129
132
|
# headers is a special key
|
130
133
|
headers.each {|k,v| easy.headers[k] = v } if headers
|
131
|
-
|
134
|
+
|
132
135
|
#
|
133
136
|
# use the remaining options as specific configuration to the easy handle
|
134
137
|
# bad options should raise an undefined method error
|
@@ -144,7 +147,7 @@ module Curl
|
|
144
147
|
|
145
148
|
max_connects.times do
|
146
149
|
conf = urls_with_config.pop
|
147
|
-
add_free_handle.call
|
150
|
+
add_free_handle.call(conf, nil) if conf
|
148
151
|
break if urls_with_config.empty?
|
149
152
|
end
|
150
153
|
|
@@ -153,7 +156,7 @@ module Curl
|
|
153
156
|
if urls_with_config.size > 0 && free_handles.size > 0
|
154
157
|
easy = free_handles.pop
|
155
158
|
conf = urls_with_config.pop
|
156
|
-
add_free_handle.call
|
159
|
+
add_free_handle.call(conf, easy) if conf
|
157
160
|
end
|
158
161
|
end
|
159
162
|
|
@@ -168,6 +171,7 @@ module Curl
|
|
168
171
|
end
|
169
172
|
free_handles = nil
|
170
173
|
end
|
174
|
+
|
171
175
|
end
|
172
176
|
|
173
177
|
# call-seq:
|
@@ -175,7 +179,7 @@ module Curl
|
|
175
179
|
# Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
|
176
180
|
#
|
177
181
|
# will create 2 new files file1.txt and file2.txt
|
178
|
-
#
|
182
|
+
#
|
179
183
|
# 2 files will be opened, and remain open until the call completes
|
180
184
|
#
|
181
185
|
# when using the :post or :put method, urls should be a hash, including the individual post fields per post
|
@@ -240,9 +244,51 @@ 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
|
253
|
+
end
|
245
254
|
|
255
|
+
def cancel!
|
256
|
+
requests.each do |_,easy|
|
257
|
+
remove(easy)
|
258
|
+
end
|
246
259
|
end
|
260
|
+
|
261
|
+
def idle?
|
262
|
+
requests.empty?
|
263
|
+
end
|
264
|
+
|
265
|
+
def requests
|
266
|
+
@requests ||= {}
|
267
|
+
end
|
268
|
+
|
269
|
+
def add(easy)
|
270
|
+
return self if requests[easy.object_id]
|
271
|
+
requests[easy.object_id] = easy
|
272
|
+
_add(easy)
|
273
|
+
self
|
274
|
+
end
|
275
|
+
|
276
|
+
def remove(easy)
|
277
|
+
return self if !requests[easy.object_id]
|
278
|
+
requests.delete(easy.object_id)
|
279
|
+
_remove(easy)
|
280
|
+
self
|
281
|
+
end
|
282
|
+
|
283
|
+
def close
|
284
|
+
requests.values.each {|easy|
|
285
|
+
_remove(easy)
|
286
|
+
}
|
287
|
+
@requests = {}
|
288
|
+
_close
|
289
|
+
self
|
290
|
+
end
|
291
|
+
|
292
|
+
|
247
293
|
end
|
248
294
|
end
|
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'
|
@@ -6,14 +7,22 @@ require 'cgi'
|
|
6
7
|
|
7
8
|
# expose shortcut methods
|
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
|
@@ -47,14 +56,13 @@ module Curl
|
|
47
56
|
end
|
48
57
|
|
49
58
|
def self.urlalize(url, params={})
|
50
|
-
|
51
|
-
if
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
59
|
+
uri = URI(url)
|
60
|
+
# early return if we didn't specify any extra params
|
61
|
+
return uri.to_s if (params || {}).empty?
|
62
|
+
|
63
|
+
params_query = URI.encode_www_form(params || {})
|
64
|
+
uri.query = [uri.query.to_s, params_query].reject(&:empty?).join('&')
|
65
|
+
uri.to_s
|
58
66
|
end
|
59
67
|
|
60
68
|
def self.postalize(params={})
|
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
|