curb 0.8.5 → 0.9.11
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.markdown +277 -0
- data/Rakefile +29 -18
- data/ext/banned.h +32 -0
- data/ext/curb.c +148 -46
- data/ext/curb.h +14 -10
- data/ext/curb_easy.c +582 -98
- data/ext/curb_easy.h +6 -0
- data/ext/curb_errors.c +113 -16
- data/ext/curb_errors.h +8 -5
- data/ext/curb_macros.h +7 -7
- data/ext/curb_multi.c +175 -167
- data/ext/curb_multi.h +0 -1
- data/ext/curb_upload.c +2 -2
- data/ext/extconf.rb +46 -17
- data/lib/curb.rb +1 -0
- data/lib/curl/easy.rb +77 -59
- data/lib/curl/multi.rb +59 -20
- data/lib/curl.rb +14 -9
- data/tests/bug_crash_on_progress.rb +41 -1
- data/tests/bug_issue102.rb +17 -0
- data/tests/bug_issue277.rb +32 -0
- data/tests/helper.rb +102 -13
- data/tests/tc_curl.rb +31 -1
- data/tests/tc_curl_download.rb +4 -4
- data/tests/tc_curl_easy.rb +195 -45
- data/tests/tc_curl_easy_resolve.rb +16 -0
- data/tests/tc_curl_maxfilesize.rb +12 -0
- data/tests/tc_curl_multi.rb +82 -16
- data/tests/tc_curl_postfield.rb +29 -29
- data/tests/timeout.rb +10 -2
- metadata +52 -46
- data/README +0 -194
data/ext/extconf.rb
CHANGED
|
@@ -59,6 +59,9 @@ def have_constant(name)
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
have_constant "curlopt_tcp_keepalive"
|
|
63
|
+
have_constant "curlopt_tcp_keepidle"
|
|
64
|
+
have_constant "curlopt_tcp_keepintvl"
|
|
62
65
|
have_constant "curlinfo_appconnect_time"
|
|
63
66
|
have_constant "curlinfo_redirect_time"
|
|
64
67
|
have_constant "curlinfo_response_code"
|
|
@@ -66,6 +69,7 @@ have_constant "curlinfo_filetime"
|
|
|
66
69
|
have_constant "curlinfo_redirect_count"
|
|
67
70
|
have_constant "curlinfo_os_errno"
|
|
68
71
|
have_constant "curlinfo_num_connects"
|
|
72
|
+
have_constant "curlinfo_cookielist"
|
|
69
73
|
have_constant "curlinfo_ftp_entry_path"
|
|
70
74
|
have_constant "curl_version_ssl"
|
|
71
75
|
have_constant "curl_version_libz"
|
|
@@ -78,9 +82,12 @@ have_constant "curl_version_largefile"
|
|
|
78
82
|
have_constant "curl_version_idn"
|
|
79
83
|
have_constant "curl_version_sspi"
|
|
80
84
|
have_constant "curl_version_conv"
|
|
85
|
+
have_constant "curl_version_http2"
|
|
81
86
|
have_constant "curlproxy_http"
|
|
82
87
|
have_constant "curlproxy_socks4"
|
|
88
|
+
have_constant "curlproxy_socks4a"
|
|
83
89
|
have_constant "curlproxy_socks5"
|
|
90
|
+
have_constant "curlproxy_socks5_hostname"
|
|
84
91
|
have_constant "curlauth_basic"
|
|
85
92
|
have_constant "curlauth_digest"
|
|
86
93
|
have_constant "curlauth_gssnegotiate"
|
|
@@ -99,6 +106,12 @@ have_constant "curle_send_fail_rewind"
|
|
|
99
106
|
have_constant "curle_ssl_engine_initfailed"
|
|
100
107
|
have_constant "curle_login_denied"
|
|
101
108
|
|
|
109
|
+
# older than 7.10.0
|
|
110
|
+
have_constant "curlopt_nosignal"
|
|
111
|
+
|
|
112
|
+
# older than 7.16.0
|
|
113
|
+
have_constant "curlmopt_pipelining"
|
|
114
|
+
|
|
102
115
|
# older than 7.16.3
|
|
103
116
|
have_constant "curlmopt_maxconnects"
|
|
104
117
|
|
|
@@ -143,6 +156,8 @@ have_func("curl_multi_timeout")
|
|
|
143
156
|
have_func("curl_multi_fdset")
|
|
144
157
|
have_func("curl_multi_perform")
|
|
145
158
|
|
|
159
|
+
have_constant "curlopt_haproxyprotocol"
|
|
160
|
+
|
|
146
161
|
# constants
|
|
147
162
|
have_constant "curlopt_interleavefunction"
|
|
148
163
|
have_constant "curlopt_interleavedata"
|
|
@@ -207,6 +222,7 @@ have_constant "curlopt_httppost"
|
|
|
207
222
|
have_constant "curlopt_referer"
|
|
208
223
|
have_constant "curlopt_useragent"
|
|
209
224
|
have_constant "curlopt_httpheader"
|
|
225
|
+
have_constant "curlopt_proxyheader"
|
|
210
226
|
have_constant "curlopt_http200aliases"
|
|
211
227
|
have_constant "curlopt_cookie"
|
|
212
228
|
have_constant "curlopt_cookiefile"
|
|
@@ -319,6 +335,12 @@ have_constant "curl_sslversion_default"
|
|
|
319
335
|
have_constant :CURL_SSLVERSION_TLSv1
|
|
320
336
|
have_constant :CURL_SSLVERSION_SSLv2
|
|
321
337
|
have_constant :CURL_SSLVERSION_SSLv3
|
|
338
|
+
|
|
339
|
+
# Added in 7.34.0
|
|
340
|
+
have_constant :CURL_SSLVERSION_TLSv1_0
|
|
341
|
+
have_constant :CURL_SSLVERSION_TLSv1_1
|
|
342
|
+
have_constant :CURL_SSLVERSION_TLSv1_2
|
|
343
|
+
|
|
322
344
|
have_constant "curlopt_ssl_verifypeer"
|
|
323
345
|
have_constant "curlopt_cainfo"
|
|
324
346
|
have_constant "curlopt_issuercert"
|
|
@@ -352,11 +374,32 @@ have_constant "curle_not_built_in"
|
|
|
352
374
|
|
|
353
375
|
have_constant "curle_obsolete" # removed in 7.24 ?
|
|
354
376
|
|
|
377
|
+
have_constant "curle_ftp_pret_failed"
|
|
378
|
+
have_constant "curle_rtsp_cseq_error"
|
|
379
|
+
have_constant "curle_rtsp_session_error"
|
|
380
|
+
have_constant "curle_ftp_bad_file_list"
|
|
381
|
+
have_constant "curle_chunk_failed"
|
|
382
|
+
have_constant "curle_no_connection_available"
|
|
383
|
+
have_constant "curle_ssl_pinnedpubkeynotmatch"
|
|
384
|
+
have_constant "curle_ssl_invalidcertstatus"
|
|
385
|
+
have_constant "curle_http2_stream"
|
|
386
|
+
|
|
355
387
|
# gssapi/spnego delegation related constants
|
|
356
388
|
have_constant "curlopt_gssapi_delegation"
|
|
357
389
|
have_constant "curlgssapi_delegation_policy_flag"
|
|
358
390
|
have_constant "curlgssapi_delegation_flag"
|
|
359
391
|
|
|
392
|
+
have_constant "CURLM_ADDED_ALREADY"
|
|
393
|
+
|
|
394
|
+
# added in 7.40.0
|
|
395
|
+
have_constant "curlopt_unix_socket_path"
|
|
396
|
+
|
|
397
|
+
# added in 7.42.0
|
|
398
|
+
have_constant "curlopt_path_as_is"
|
|
399
|
+
|
|
400
|
+
# added in 7.43.0
|
|
401
|
+
have_constant "curlopt_pipewait"
|
|
402
|
+
|
|
360
403
|
if try_compile('int main() { return 0; }','-Wall')
|
|
361
404
|
$CFLAGS << ' -Wall'
|
|
362
405
|
end
|
|
@@ -372,23 +415,6 @@ def test_for(name, const, src)
|
|
|
372
415
|
end
|
|
373
416
|
end
|
|
374
417
|
end
|
|
375
|
-
test_for("Ruby 1.9 Hash", "RUBY19_HASH", %{
|
|
376
|
-
#include <ruby.h>
|
|
377
|
-
int main() {
|
|
378
|
-
VALUE hash = rb_hash_new();
|
|
379
|
-
if( RHASH(hash)->ntbl->num_entries ) {
|
|
380
|
-
return 0;
|
|
381
|
-
}
|
|
382
|
-
return 1;
|
|
383
|
-
}
|
|
384
|
-
})
|
|
385
|
-
test_for("Ruby 1.9 st.h", "RUBY19_ST_H", %{
|
|
386
|
-
#include <ruby.h>
|
|
387
|
-
#include <ruby/st.h>
|
|
388
|
-
int main() {
|
|
389
|
-
return 0;
|
|
390
|
-
}
|
|
391
|
-
})
|
|
392
418
|
|
|
393
419
|
test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
|
|
394
420
|
#include <curl/curl.h>
|
|
@@ -400,6 +426,9 @@ test_for("curl_easy_escape", "CURL_EASY_ESCAPE", %{
|
|
|
400
426
|
})
|
|
401
427
|
|
|
402
428
|
have_func('rb_thread_blocking_region')
|
|
429
|
+
have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
|
430
|
+
have_header('ruby/io.h')
|
|
431
|
+
have_func('rb_io_stdio_file')
|
|
403
432
|
|
|
404
433
|
create_header('curb_config.h')
|
|
405
434
|
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
|
|
|
@@ -6,31 +7,41 @@ module Curl
|
|
|
6
7
|
alias body body_str
|
|
7
8
|
alias head header_str
|
|
8
9
|
|
|
10
|
+
class Error < StandardError
|
|
11
|
+
attr_accessor :message, :code
|
|
12
|
+
def initialize(code, msg)
|
|
13
|
+
self.message = msg
|
|
14
|
+
self.code = code
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
9
18
|
#
|
|
10
19
|
# call-seq:
|
|
11
20
|
# easy.status => String
|
|
12
21
|
#
|
|
13
22
|
def status
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
while parts.size > 0 && parts.first != ''
|
|
18
|
-
status << parts.shift
|
|
19
|
-
end
|
|
20
|
-
status.join(' ')
|
|
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.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map{ |match| match[1] }
|
|
25
|
+
statuses.last.strip if statuses.length > 0
|
|
21
26
|
end
|
|
22
27
|
|
|
23
28
|
#
|
|
24
29
|
# call-seq:
|
|
25
30
|
# easy.set :sym|Fixnum, value
|
|
26
|
-
#
|
|
31
|
+
#
|
|
27
32
|
# set options on the curl easy handle see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
|
|
28
33
|
#
|
|
29
34
|
def set(opt,val)
|
|
30
35
|
if opt.is_a?(Symbol)
|
|
31
|
-
|
|
36
|
+
option = sym2curl(opt)
|
|
32
37
|
else
|
|
33
|
-
|
|
38
|
+
option = opt.to_i
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
setopt(option, val)
|
|
43
|
+
rescue TypeError
|
|
44
|
+
raise TypeError, "Curb doesn't support setting #{opt} [##{option}] option"
|
|
34
45
|
end
|
|
35
46
|
end
|
|
36
47
|
|
|
@@ -56,10 +67,16 @@ module Curl
|
|
|
56
67
|
self.multi = Curl::Multi.new if self.multi.nil?
|
|
57
68
|
self.multi.add self
|
|
58
69
|
ret = self.multi.perform
|
|
70
|
+
self.multi.remove self
|
|
71
|
+
|
|
72
|
+
if Curl::Multi.autoclose
|
|
73
|
+
self.multi.close
|
|
74
|
+
self.multi = nil
|
|
75
|
+
end
|
|
59
76
|
|
|
60
77
|
if self.last_result != 0 && self.on_failure.nil?
|
|
61
|
-
error = Curl::Easy.error(self.last_result)
|
|
62
|
-
raise error.first
|
|
78
|
+
error = Curl::Easy.error(self.last_result)
|
|
79
|
+
raise error.first.new(self.head)
|
|
63
80
|
end
|
|
64
81
|
|
|
65
82
|
ret
|
|
@@ -83,54 +100,55 @@ module Curl
|
|
|
83
100
|
# easy.perform
|
|
84
101
|
#
|
|
85
102
|
def delete=(onoff)
|
|
86
|
-
set :customrequest, onoff ? '
|
|
103
|
+
set :customrequest, onoff ? 'DELETE' : nil
|
|
87
104
|
onoff
|
|
88
105
|
end
|
|
89
|
-
#
|
|
106
|
+
#
|
|
90
107
|
# call-seq:
|
|
91
|
-
#
|
|
108
|
+
#
|
|
92
109
|
# easy = Curl::Easy.new("url")
|
|
110
|
+
# easy.version = Curl::HTTP_2_0
|
|
93
111
|
# easy.version = Curl::HTTP_1_1
|
|
94
112
|
# easy.version = Curl::HTTP_1_0
|
|
95
113
|
# easy.version = Curl::HTTP_NONE
|
|
96
|
-
#
|
|
114
|
+
#
|
|
97
115
|
def version=(http_version)
|
|
98
116
|
set :http_version, http_version
|
|
99
117
|
end
|
|
100
118
|
|
|
101
|
-
#
|
|
119
|
+
#
|
|
102
120
|
# call-seq:
|
|
103
121
|
# easy.url = "http://some.url/" => "http://some.url/"
|
|
104
|
-
#
|
|
122
|
+
#
|
|
105
123
|
# Set the URL for subsequent calls to +perform+. It is acceptable
|
|
106
124
|
# (and even recommended) to reuse Curl::Easy instances by reassigning
|
|
107
125
|
# the URL between calls to +perform+.
|
|
108
|
-
#
|
|
126
|
+
#
|
|
109
127
|
def url=(u)
|
|
110
128
|
set :url, u
|
|
111
129
|
end
|
|
112
130
|
|
|
113
|
-
#
|
|
131
|
+
#
|
|
114
132
|
# call-seq:
|
|
115
133
|
# easy.proxy_url = string => string
|
|
116
|
-
#
|
|
134
|
+
#
|
|
117
135
|
# Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
|
|
118
136
|
# The URL should specify the the host name or dotted IP address. To specify
|
|
119
137
|
# port number in this string, append :[port] to the end of the host name.
|
|
120
138
|
# The proxy string may be prefixed with [protocol]:// since any such prefix
|
|
121
139
|
# will be ignored. The proxy's port number may optionally be specified with
|
|
122
140
|
# the separate option proxy_port .
|
|
123
|
-
#
|
|
141
|
+
#
|
|
124
142
|
# When you tell the library to use an HTTP proxy, libcurl will transparently
|
|
125
143
|
# convert operations to HTTP even if you specify an FTP URL etc. This may have
|
|
126
144
|
# an impact on what other features of the library you can use, such as
|
|
127
145
|
# FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
|
|
128
146
|
# tunneling is activated with proxy_tunnel = true.
|
|
129
|
-
#
|
|
147
|
+
#
|
|
130
148
|
# libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
|
|
131
149
|
# *all_proxy* etc, if any of those is set. The proxy_url option does however
|
|
132
150
|
# override any possibly set environment variables.
|
|
133
|
-
#
|
|
151
|
+
#
|
|
134
152
|
# Starting with libcurl 7.14.1, the proxy host string given in environment
|
|
135
153
|
# variables can be specified the exact same way as the proxy can be set with
|
|
136
154
|
# proxy_url, including protocol prefix (http://) and embedded user + password.
|
|
@@ -145,89 +163,89 @@ module Curl
|
|
|
145
163
|
self.ssl_verify_host_integer=value
|
|
146
164
|
end
|
|
147
165
|
|
|
148
|
-
#
|
|
166
|
+
#
|
|
149
167
|
# call-seq:
|
|
150
168
|
# easy.ssl_verify_host? => boolean
|
|
151
|
-
#
|
|
169
|
+
#
|
|
152
170
|
# Deprecated: call easy.ssl_verify_host instead
|
|
153
171
|
# can be one of [0,1,2]
|
|
154
|
-
#
|
|
172
|
+
#
|
|
155
173
|
# Determine whether this Curl instance will verify that the server cert
|
|
156
174
|
# is for the server it is known as.
|
|
157
|
-
#
|
|
175
|
+
#
|
|
158
176
|
def ssl_verify_host?
|
|
159
177
|
ssl_verify_host.nil? ? false : (ssl_verify_host > 0)
|
|
160
178
|
end
|
|
161
179
|
|
|
162
|
-
#
|
|
180
|
+
#
|
|
163
181
|
# call-seq:
|
|
164
182
|
# easy.interface = string => string
|
|
165
|
-
#
|
|
183
|
+
#
|
|
166
184
|
# Set the interface name to use as the outgoing network interface.
|
|
167
185
|
# The name can be an interface name, an IP address or a host name.
|
|
168
|
-
#
|
|
186
|
+
#
|
|
169
187
|
def interface=(value)
|
|
170
188
|
set :interface, value
|
|
171
189
|
end
|
|
172
190
|
|
|
173
|
-
#
|
|
191
|
+
#
|
|
174
192
|
# call-seq:
|
|
175
193
|
# easy.userpwd = string => string
|
|
176
|
-
#
|
|
194
|
+
#
|
|
177
195
|
# Set the username/password string to use for subsequent calls to +perform+.
|
|
178
196
|
# The supplied string should have the form "username:password"
|
|
179
|
-
#
|
|
197
|
+
#
|
|
180
198
|
def userpwd=(value)
|
|
181
199
|
set :userpwd, value
|
|
182
200
|
end
|
|
183
201
|
|
|
184
|
-
#
|
|
202
|
+
#
|
|
185
203
|
# call-seq:
|
|
186
204
|
# easy.proxypwd = string => string
|
|
187
|
-
#
|
|
205
|
+
#
|
|
188
206
|
# Set the username/password string to use for proxy connection during
|
|
189
207
|
# subsequent calls to +perform+. The supplied string should have the
|
|
190
208
|
# form "username:password"
|
|
191
|
-
#
|
|
209
|
+
#
|
|
192
210
|
def proxypwd=(value)
|
|
193
211
|
set :proxyuserpwd, value
|
|
194
212
|
end
|
|
195
213
|
|
|
196
|
-
#
|
|
214
|
+
#
|
|
197
215
|
# call-seq:
|
|
198
216
|
# easy.cookies = "name1=content1; name2=content2;" => string
|
|
199
|
-
#
|
|
217
|
+
#
|
|
200
218
|
# Set cookies to be sent by this Curl::Easy instance. The format of the string should
|
|
201
219
|
# be NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie should contain.
|
|
202
220
|
# Set multiple cookies in one string like this: "name1=content1; name2=content2;" etc.
|
|
203
|
-
#
|
|
221
|
+
#
|
|
204
222
|
def cookies=(value)
|
|
205
223
|
set :cookie, value
|
|
206
224
|
end
|
|
207
225
|
|
|
208
|
-
#
|
|
226
|
+
#
|
|
209
227
|
# call-seq:
|
|
210
228
|
# easy.cookiefile = string => string
|
|
211
|
-
#
|
|
229
|
+
#
|
|
212
230
|
# Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
|
|
213
|
-
#
|
|
231
|
+
#
|
|
214
232
|
# *Note* that you must set enable_cookies true to enable the cookie
|
|
215
233
|
# engine, or this option will be ignored.
|
|
216
|
-
#
|
|
234
|
+
#
|
|
217
235
|
def cookiefile=(value)
|
|
218
236
|
set :cookiefile, value
|
|
219
237
|
end
|
|
220
238
|
|
|
221
|
-
#
|
|
239
|
+
#
|
|
222
240
|
# call-seq:
|
|
223
241
|
# easy.cookiejar = string => string
|
|
224
|
-
#
|
|
242
|
+
#
|
|
225
243
|
# Set a cookiejar file to use for this Curl::Easy instance.
|
|
226
244
|
# Cookies from the response will be written into this file.
|
|
227
|
-
#
|
|
245
|
+
#
|
|
228
246
|
# *Note* that you must set enable_cookies true to enable the cookie
|
|
229
247
|
# engine, or this option will be ignored.
|
|
230
|
-
#
|
|
248
|
+
#
|
|
231
249
|
def cookiejar=(value)
|
|
232
250
|
set :cookiejar, value
|
|
233
251
|
end
|
|
@@ -405,35 +423,35 @@ module Curl
|
|
|
405
423
|
c.http_delete
|
|
406
424
|
c
|
|
407
425
|
end
|
|
408
|
-
|
|
426
|
+
|
|
409
427
|
# call-seq:
|
|
410
428
|
# Curl::Easy.download(url, filename = url.split(/\?/).first.split(/\//).last) { |curl| ... }
|
|
411
|
-
#
|
|
429
|
+
#
|
|
412
430
|
# Stream the specified url (via perform) and save the data directly to the
|
|
413
|
-
# supplied filename (defaults to the last component of the URL path, which will
|
|
431
|
+
# supplied filename (defaults to the last component of the URL path, which will
|
|
414
432
|
# usually be the filename most simple urls).
|
|
415
|
-
#
|
|
433
|
+
#
|
|
416
434
|
# If a block is supplied, it will be passed the curl instance prior to the
|
|
417
435
|
# perform call.
|
|
418
|
-
#
|
|
436
|
+
#
|
|
419
437
|
# *Note* that the semantics of the on_body handler are subtly changed when using
|
|
420
|
-
# download, to account for the automatic routing of data to the specified file: The
|
|
438
|
+
# download, to account for the automatic routing of data to the specified file: The
|
|
421
439
|
# data string is passed to the handler *before* it is written
|
|
422
|
-
# to the file, allowing the handler to perform mutative operations where
|
|
440
|
+
# to the file, allowing the handler to perform mutative operations where
|
|
423
441
|
# necessary. As usual, the transfer will be aborted if the on_body handler
|
|
424
|
-
# returns a size that differs from the data chunk size - in this case, the
|
|
442
|
+
# returns a size that differs from the data chunk size - in this case, the
|
|
425
443
|
# offending chunk will *not* be written to the file, the file will be closed,
|
|
426
444
|
# and a Curl::Err::AbortedByCallbackError will be raised.
|
|
427
445
|
def download(url, filename = url.split(/\?/).first.split(/\//).last, &blk)
|
|
428
446
|
curl = Curl::Easy.new(url, &blk)
|
|
429
|
-
|
|
447
|
+
|
|
430
448
|
output = if filename.is_a? IO
|
|
431
449
|
filename.binmode if filename.respond_to?(:binmode)
|
|
432
450
|
filename
|
|
433
451
|
else
|
|
434
452
|
File.open(filename, 'wb')
|
|
435
453
|
end
|
|
436
|
-
|
|
454
|
+
|
|
437
455
|
begin
|
|
438
456
|
old_on_body = curl.on_body do |data|
|
|
439
457
|
result = old_on_body ? old_on_body.call(data) : data.length
|
|
@@ -444,7 +462,7 @@ module Curl
|
|
|
444
462
|
ensure
|
|
445
463
|
output.close rescue IOError
|
|
446
464
|
end
|
|
447
|
-
|
|
465
|
+
|
|
448
466
|
return curl
|
|
449
467
|
end
|
|
450
468
|
end
|
data/lib/curl/multi.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Curl
|
|
2
|
-
|
|
3
3
|
class Multi
|
|
4
4
|
class << self
|
|
5
5
|
# call-seq:
|
|
6
|
-
# Curl::Multi.get('url1','url2','url3','url4','url5', :follow_location => true) do|easy|
|
|
6
|
+
# Curl::Multi.get(['url1','url2','url3','url4','url5'], :follow_location => true) do|easy|
|
|
7
7
|
# easy
|
|
8
8
|
# end
|
|
9
|
-
#
|
|
9
|
+
#
|
|
10
10
|
# Blocking call to fetch multiple url's in parallel.
|
|
11
11
|
def get(urls, easy_options={}, multi_options={}, &blk)
|
|
12
12
|
url_confs = []
|
|
@@ -22,13 +22,13 @@ module Curl
|
|
|
22
22
|
# {:url => 'url2', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
|
|
23
23
|
# {:url => 'url3', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}}],
|
|
24
24
|
# { :follow_location => true, :multipart_form_post => true },
|
|
25
|
-
# {:pipeline =>
|
|
25
|
+
# {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
|
|
26
26
|
# easy_handle_on_request_complete
|
|
27
27
|
# end
|
|
28
|
-
#
|
|
28
|
+
#
|
|
29
29
|
# 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
|
|
30
|
+
#
|
|
31
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
|
32
32
|
# easy_options: are a set of common options to set on all easy handles
|
|
33
33
|
# multi_options: options to set on the Curl::Multi handle
|
|
34
34
|
#
|
|
@@ -46,13 +46,13 @@ module Curl
|
|
|
46
46
|
# {:url => 'url2', :put_data => IO.read('filepath')},
|
|
47
47
|
# {:url => 'url3', :put_data => "maybe another string or socket?"],
|
|
48
48
|
# {:follow_location => true},
|
|
49
|
-
# {:pipeline =>
|
|
49
|
+
# {:pipeline => Curl::CURLPIPE_HTTP1}) do|easy|
|
|
50
50
|
# easy_handle_on_request_complete
|
|
51
51
|
# end
|
|
52
|
-
#
|
|
52
|
+
#
|
|
53
53
|
# 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
|
|
54
|
+
#
|
|
55
|
+
# urls_with_config: is a hash of url's pointing to the postfields to send
|
|
56
56
|
# easy_options: are a set of common options to set on all easy handles
|
|
57
57
|
# multi_options: options to set on the Curl::Multi handle
|
|
58
58
|
#
|
|
@@ -74,12 +74,12 @@ module Curl
|
|
|
74
74
|
# :follow_location => true, :max_redirects => 3 },
|
|
75
75
|
# { :url => 'url3', :method => :put, :put_data => File.open('file.txt','rb') },
|
|
76
76
|
# { :url => 'url4', :method => :head }
|
|
77
|
-
# ], {:pipeline =>
|
|
77
|
+
# ], {:pipeline => Curl::CURLPIPE_HTTP1})
|
|
78
78
|
#
|
|
79
79
|
# Blocking call to issue multiple HTTP requests with varying verb's.
|
|
80
80
|
#
|
|
81
81
|
# 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
|
|
82
|
+
# multi_options: options for the multi handle
|
|
83
83
|
# blk: a callback, that yeilds when a handle is completed
|
|
84
84
|
#
|
|
85
85
|
def http(urls_with_config, multi_options={}, &blk)
|
|
@@ -92,7 +92,7 @@ module Curl
|
|
|
92
92
|
|
|
93
93
|
# configure the multi handle
|
|
94
94
|
multi_options.each { |k,v| m.send("#{k}=", v) }
|
|
95
|
-
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_body,:on_header]
|
|
95
|
+
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_redirect,:on_body,:on_header]
|
|
96
96
|
|
|
97
97
|
add_free_handle = proc do|conf, easy|
|
|
98
98
|
c = conf.dup # avoid being destructive to input
|
|
@@ -128,23 +128,23 @@ module Curl
|
|
|
128
128
|
|
|
129
129
|
# headers is a special key
|
|
130
130
|
headers.each {|k,v| easy.headers[k] = v } if headers
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
#
|
|
133
133
|
# use the remaining options as specific configuration to the easy handle
|
|
134
134
|
# bad options should raise an undefined method error
|
|
135
135
|
#
|
|
136
136
|
c.each { |k,v| easy.send("#{k}=",v) }
|
|
137
137
|
|
|
138
|
-
easy.on_complete {|curl
|
|
138
|
+
easy.on_complete {|curl|
|
|
139
139
|
free_handles << curl
|
|
140
|
-
blk.call(curl,
|
|
140
|
+
blk.call(curl,curl.response_code,method) if blk
|
|
141
141
|
}
|
|
142
142
|
m.add(easy)
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
max_connects.times do
|
|
146
146
|
conf = urls_with_config.pop
|
|
147
|
-
add_free_handle.call
|
|
147
|
+
add_free_handle.call(conf, nil) if conf
|
|
148
148
|
break if urls_with_config.empty?
|
|
149
149
|
end
|
|
150
150
|
|
|
@@ -153,7 +153,7 @@ module Curl
|
|
|
153
153
|
if urls_with_config.size > 0 && free_handles.size > 0
|
|
154
154
|
easy = free_handles.pop
|
|
155
155
|
conf = urls_with_config.pop
|
|
156
|
-
add_free_handle.call
|
|
156
|
+
add_free_handle.call(conf, easy) if conf
|
|
157
157
|
end
|
|
158
158
|
end
|
|
159
159
|
|
|
@@ -168,6 +168,7 @@ module Curl
|
|
|
168
168
|
end
|
|
169
169
|
free_handles = nil
|
|
170
170
|
end
|
|
171
|
+
|
|
171
172
|
end
|
|
172
173
|
|
|
173
174
|
# call-seq:
|
|
@@ -175,7 +176,7 @@ module Curl
|
|
|
175
176
|
# Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
|
|
176
177
|
#
|
|
177
178
|
# will create 2 new files file1.txt and file2.txt
|
|
178
|
-
#
|
|
179
|
+
#
|
|
179
180
|
# 2 files will be opened, and remain open until the call completes
|
|
180
181
|
#
|
|
181
182
|
# when using the :post or :put method, urls should be a hash, including the individual post fields per post
|
|
@@ -242,7 +243,45 @@ module Curl
|
|
|
242
243
|
}
|
|
243
244
|
raise errors unless errors.empty?
|
|
244
245
|
end
|
|
246
|
+
end
|
|
245
247
|
|
|
248
|
+
def cancel!
|
|
249
|
+
requests.each do |_,easy|
|
|
250
|
+
remove(easy)
|
|
251
|
+
end
|
|
246
252
|
end
|
|
253
|
+
|
|
254
|
+
def idle?
|
|
255
|
+
requests.empty?
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def requests
|
|
259
|
+
@requests ||= {}
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def add(easy)
|
|
263
|
+
return self if requests[easy.object_id]
|
|
264
|
+
requests[easy.object_id] = easy
|
|
265
|
+
_add(easy)
|
|
266
|
+
self
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def remove(easy)
|
|
270
|
+
return self if !requests[easy.object_id]
|
|
271
|
+
requests.delete(easy.object_id)
|
|
272
|
+
_remove(easy)
|
|
273
|
+
self
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def close
|
|
277
|
+
requests.values.each {|easy|
|
|
278
|
+
_remove(easy)
|
|
279
|
+
}
|
|
280
|
+
@requests = {}
|
|
281
|
+
_close
|
|
282
|
+
self
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
|
|
247
286
|
end
|
|
248
287
|
end
|
data/lib/curl.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'curb_core'
|
|
2
3
|
require 'curl/easy'
|
|
3
4
|
require 'curl/multi'
|
|
4
5
|
require 'uri'
|
|
6
|
+
require 'cgi'
|
|
5
7
|
|
|
6
8
|
# expose shortcut methods
|
|
7
9
|
module Curl
|
|
8
|
-
|
|
10
|
+
|
|
9
11
|
def self.http(verb, url, post_body=nil, put_data=nil, &block)
|
|
10
12
|
handle = Thread.current[:curb_curl] ||= Curl::Easy.new
|
|
11
13
|
handle.reset
|
|
@@ -46,18 +48,21 @@ module Curl
|
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
def self.urlalize(url, params={})
|
|
49
|
-
|
|
50
|
-
if
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
51
|
+
uri = URI(url)
|
|
52
|
+
# early return if we didn't specify any extra params
|
|
53
|
+
return uri.to_s if (params || {}).empty?
|
|
54
|
+
|
|
55
|
+
params_query = URI.encode_www_form(params || {})
|
|
56
|
+
uri.query = [uri.query.to_s, params_query].reject(&:empty?).join('&')
|
|
57
|
+
uri.to_s
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
def self.postalize(params={})
|
|
60
61
|
params.respond_to?(:map) ? URI.encode_www_form(params) : (params.respond_to?(:to_s) ? params.to_s : params)
|
|
61
62
|
end
|
|
62
63
|
|
|
64
|
+
def self.reset
|
|
65
|
+
Thread.current[:curb_curl] = Curl::Easy.new
|
|
66
|
+
end
|
|
67
|
+
|
|
63
68
|
end
|