curb 0.8.5 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +579 -0
- data/Rakefile +85 -27
- data/doc.rb +48 -8
- data/ext/banned.h +32 -0
- data/ext/curb.c +563 -233
- data/ext/curb.h +19 -10
- data/ext/curb_easy.c +3229 -368
- data/ext/curb_easy.h +42 -0
- data/ext/curb_errors.c +117 -18
- data/ext/curb_errors.h +9 -5
- data/ext/curb_macros.h +33 -21
- data/ext/curb_multi.c +1904 -272
- data/ext/curb_multi.h +11 -3
- data/ext/curb_postfield.c +149 -77
- data/ext/curb_postfield.h +1 -0
- data/ext/curb_upload.c +38 -11
- data/ext/curb_upload.h +2 -0
- data/ext/extconf.rb +355 -35
- data/lib/curb.rb +1 -0
- data/lib/curl/download.rb +160 -0
- data/lib/curl/easy.rb +422 -88
- data/lib/curl/multi.rb +295 -56
- data/lib/curl.rb +676 -11
- data/tests/bug_crash_on_debug.rb +14 -28
- data/tests/bug_crash_on_progress.rb +32 -16
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +10 -15
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +6 -30
- data/tests/bug_follow_redirect_288.rb +83 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +3 -5
- data/tests/bug_issue102.rb +17 -0
- data/tests/bug_issue_noproxy.rb +56 -0
- data/tests/bug_issue_post_redirect.rb +93 -0
- data/tests/bug_issue_spnego.rb +41 -0
- data/tests/bug_multi_segfault.rb +1 -0
- data/tests/bug_poison.rb +29 -0
- data/tests/bug_raise_on_callback.rb +30 -0
- data/tests/helper.rb +400 -44
- data/tests/leak_trace.rb +237 -0
- data/tests/mem_check.rb +3 -0
- data/tests/tc_curl.rb +31 -1
- data/tests/tc_curl_download.rb +98 -7
- data/tests/tc_curl_easy.rb +985 -66
- data/tests/tc_curl_easy_cookielist.rb +277 -0
- data/tests/tc_curl_easy_request_target.rb +41 -0
- data/tests/tc_curl_easy_resolve.rb +48 -0
- data/tests/tc_curl_maxfilesize.rb +212 -0
- data/tests/tc_curl_multi.rb +1111 -51
- data/tests/tc_curl_native_coverage.rb +145 -0
- data/tests/tc_curl_network_policy.rb +1475 -0
- data/tests/tc_curl_postfield.rb +207 -30
- data/tests/tc_curl_protocols.rb +388 -0
- data/tests/tc_fiber_scheduler.rb +584 -0
- data/tests/tc_ftp_options.rb +39 -0
- data/tests/tc_gc_compact.rb +223 -0
- data/tests/tc_test_server_methods.rb +110 -0
- data/tests/timeout.rb +30 -6
- metadata +66 -31
- data/README +0 -194
data/lib/curl/easy.rb
CHANGED
|
@@ -1,36 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'curl/download'
|
|
1
3
|
module Curl
|
|
2
4
|
class Easy
|
|
5
|
+
class << self
|
|
6
|
+
def deferred_multi_close_mutex
|
|
7
|
+
@deferred_multi_close_mutex ||= Mutex.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def deferred_multi_closes
|
|
11
|
+
deferred_multi_close_mutex.synchronize do
|
|
12
|
+
(@deferred_multi_closes ||= []).dup
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def release_deferred_multi_close(multi, easy)
|
|
17
|
+
if easy && multi.requests[easy.object_id]
|
|
18
|
+
begin
|
|
19
|
+
multi.remove(easy)
|
|
20
|
+
rescue StandardError
|
|
21
|
+
# Deferred cleanup only applies to implicit single-easy multis, so
|
|
22
|
+
# clear any stale Ruby bookkeeping and continue closing the handle.
|
|
23
|
+
multi.instance_variable_set(:@requests, {})
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
multi.instance_variable_set(:@requests, {})
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
multi.instance_variable_set(:@deferred_close, false)
|
|
30
|
+
multi._close
|
|
31
|
+
true
|
|
32
|
+
rescue StandardError
|
|
33
|
+
false
|
|
34
|
+
end
|
|
3
35
|
|
|
36
|
+
def defer_multi_close(multi, easy, owner: Thread.current)
|
|
37
|
+
deferred_multi_close_mutex.synchronize do
|
|
38
|
+
@deferred_multi_closes ||= []
|
|
39
|
+
return if @deferred_multi_closes.any? { |entry| entry[:multi].equal?(multi) }
|
|
40
|
+
|
|
41
|
+
multi.instance_variable_set(:@deferred_close, true)
|
|
42
|
+
@deferred_multi_closes << { multi: multi, easy: easy, owner: owner }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def flush_deferred_multi_closes(all_threads: false)
|
|
47
|
+
pending = deferred_multi_close_mutex.synchronize do
|
|
48
|
+
@deferred_multi_closes ||= []
|
|
49
|
+
|
|
50
|
+
if all_threads
|
|
51
|
+
@deferred_multi_closes.shift(@deferred_multi_closes.length)
|
|
52
|
+
else
|
|
53
|
+
owner = Thread.current
|
|
54
|
+
remaining = []
|
|
55
|
+
current = []
|
|
56
|
+
|
|
57
|
+
@deferred_multi_closes.each do |entry|
|
|
58
|
+
if entry[:owner].equal?(owner)
|
|
59
|
+
current << entry
|
|
60
|
+
else
|
|
61
|
+
remaining << entry
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@deferred_multi_closes = remaining
|
|
66
|
+
current
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
pending.each do |entry|
|
|
71
|
+
multi = entry[:multi]
|
|
72
|
+
easy = entry[:easy]
|
|
73
|
+
|
|
74
|
+
unless release_deferred_multi_close(multi, easy)
|
|
75
|
+
defer_multi_close(multi, easy, owner: entry[:owner])
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
at_exit do
|
|
82
|
+
flush_deferred_multi_closes(all_threads: true)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
alias_method :_curb_native_close, :close
|
|
86
|
+
alias_method :_curb_native_multi_set, :multi=
|
|
87
|
+
alias_method :_curb_native_reset, :reset
|
|
88
|
+
|
|
89
|
+
def close
|
|
90
|
+
previous_multi = self.multi
|
|
91
|
+
result = _curb_native_close
|
|
92
|
+
__curb_clear_safety_override!
|
|
93
|
+
previous_multi.__send__(:__unregister_idle_easy_reference, self) if previous_multi
|
|
94
|
+
result
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def multi=(multi)
|
|
98
|
+
previous_multi = self.multi
|
|
99
|
+
return multi if previous_multi.equal?(multi)
|
|
100
|
+
|
|
101
|
+
if previous_multi && previous_multi.requests[self.object_id]
|
|
102
|
+
previous_multi.remove(self)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
result = _curb_native_multi_set(multi)
|
|
106
|
+
previous_multi.__send__(:__unregister_idle_easy_reference, self) if previous_multi
|
|
107
|
+
multi.__send__(:__register_idle_easy_reference, self) if multi
|
|
108
|
+
result
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def reset
|
|
112
|
+
result = _curb_native_reset
|
|
113
|
+
__curb_clear_safety_override!
|
|
114
|
+
result
|
|
115
|
+
end
|
|
116
|
+
|
|
4
117
|
alias post http_post
|
|
5
118
|
alias put http_put
|
|
6
119
|
alias body body_str
|
|
7
120
|
alias head header_str
|
|
8
121
|
|
|
122
|
+
class Error < StandardError
|
|
123
|
+
attr_accessor :message, :code
|
|
124
|
+
def initialize(code, msg)
|
|
125
|
+
self.message = msg
|
|
126
|
+
self.code = code
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
9
130
|
#
|
|
10
131
|
# call-seq:
|
|
11
132
|
# easy.status => String
|
|
12
133
|
#
|
|
13
134
|
def status
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
while parts.size > 0 && parts.first != ''
|
|
18
|
-
status << parts.shift
|
|
19
|
-
end
|
|
20
|
-
status.join(' ')
|
|
135
|
+
# Matches the last HTTP Status - following the HTTP protocol specification 'Status-Line = HTTP-Version SP Status-Code SP (Opt:)Reason-Phrase CRLF'
|
|
136
|
+
statuses = self.header_str.to_s.scan(/HTTP\/\d(\.\d)?\s(\d+\s.*)\r\n/).map {|match| match[1] }
|
|
137
|
+
statuses.last.strip if statuses.length > 0
|
|
21
138
|
end
|
|
22
139
|
|
|
23
140
|
#
|
|
24
141
|
# call-seq:
|
|
25
142
|
# easy.set :sym|Fixnum, value
|
|
26
|
-
#
|
|
143
|
+
#
|
|
27
144
|
# set options on the curl easy handle see http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
|
|
28
145
|
#
|
|
29
146
|
def set(opt,val)
|
|
30
147
|
if opt.is_a?(Symbol)
|
|
31
|
-
|
|
148
|
+
option = sym2curl(opt)
|
|
32
149
|
else
|
|
33
|
-
|
|
150
|
+
option = opt.to_i
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
begin
|
|
154
|
+
setopt(option, val)
|
|
155
|
+
rescue TypeError
|
|
156
|
+
raise TypeError, "Curb doesn't support setting #{opt} [##{option}] option"
|
|
34
157
|
end
|
|
35
158
|
end
|
|
36
159
|
|
|
@@ -44,6 +167,84 @@ module Curl
|
|
|
44
167
|
Curl.const_get("CURLOPT_#{opt.to_s.upcase}")
|
|
45
168
|
end
|
|
46
169
|
|
|
170
|
+
def allowed_protocols=(protocols)
|
|
171
|
+
set_protocol_allowlist('CURLOPT_PROTOCOLS_STR', 'CURLOPT_PROTOCOLS', protocols)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def allowed_redirect_protocols=(protocols)
|
|
175
|
+
set_protocol_allowlist('CURLOPT_REDIR_PROTOCOLS_STR', 'CURLOPT_REDIR_PROTOCOLS', protocols)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def safe_http!
|
|
179
|
+
__curb_set_safety_override!(
|
|
180
|
+
:protocols => [:http, :https],
|
|
181
|
+
:redirect_protocols => [:http, :https]
|
|
182
|
+
)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
private
|
|
186
|
+
|
|
187
|
+
def __curb_set_safety_override!(options)
|
|
188
|
+
@__curb_safety_override = (defined?(@__curb_safety_override) && @__curb_safety_override) ? @__curb_safety_override.dup : {}
|
|
189
|
+
@__curb_safety_override[:protocols] = Array(options[:protocols]).map { |protocol| protocol.to_s.downcase.to_sym } if options.key?(:protocols)
|
|
190
|
+
@__curb_safety_override[:redirect_protocols] = Array(options[:redirect_protocols]).map { |protocol| protocol.to_s.downcase.to_sym } if options.key?(:redirect_protocols)
|
|
191
|
+
@__curb_safety_override[:max_body_bytes] = options[:max_body_bytes] if options.key?(:max_body_bytes) && options[:max_body_bytes]
|
|
192
|
+
@__curb_safety_override_generation = __curb_safety_override_generation + 1
|
|
193
|
+
Curl.__send__(:apply_safety!, self) if Curl.respond_to?(:apply_safety!, true)
|
|
194
|
+
self
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def __curb_clear_safety_override!
|
|
198
|
+
had_override = defined?(@__curb_safety_override) && @__curb_safety_override
|
|
199
|
+
return unless had_override
|
|
200
|
+
return if frozen?
|
|
201
|
+
|
|
202
|
+
@__curb_safety_override = nil
|
|
203
|
+
@__curb_safety_override_generation = __curb_safety_override_generation + 1
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def __curb_safety_override
|
|
207
|
+
defined?(@__curb_safety_override) ? @__curb_safety_override : nil
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def __curb_safety_override_generation
|
|
211
|
+
defined?(@__curb_safety_override_generation) ? @__curb_safety_override_generation : 0
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def set_protocol_allowlist(string_option, bitmask_option, protocols)
|
|
215
|
+
protocol_names = Array(protocols).map { |protocol| protocol.to_s.downcase }
|
|
216
|
+
raise ArgumentError, "at least one protocol is required" if protocol_names.empty?
|
|
217
|
+
|
|
218
|
+
valid_names = %w[
|
|
219
|
+
dict file ftp ftps gopher gophers http https imap imaps ldap ldaps
|
|
220
|
+
mqtt pop3 pop3s rtmp rtmpe rtmps rtmpt rtmpte rtmpts rtsp scp sftp
|
|
221
|
+
smb smbs smtp smtps telnet tftp ws wss
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
if Curl.const_defined?(string_option)
|
|
225
|
+
protocol_names.each do |name|
|
|
226
|
+
raise ArgumentError, "unsupported protocol: #{name.inspect}" unless valid_names.include?(name)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
setopt(Curl.const_get(string_option), protocol_names.join(','))
|
|
230
|
+
elsif Curl.const_defined?(bitmask_option)
|
|
231
|
+
protocol_pairs = protocol_names.map do |name|
|
|
232
|
+
const_name = "CURLPROTO_#{name.upcase}"
|
|
233
|
+
raise ArgumentError, "unsupported protocol: #{name.inspect}" unless Curl.const_defined?(const_name)
|
|
234
|
+
|
|
235
|
+
[name, Curl.const_get(const_name)]
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
setopt(Curl.const_get(bitmask_option), protocol_pairs.inject(0) { |mask, pair| mask | pair.last })
|
|
239
|
+
else
|
|
240
|
+
raise NotImplementedError, "protocol allowlists are not supported by this libcurl"
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
protocols
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
public
|
|
247
|
+
|
|
47
248
|
#
|
|
48
249
|
# call-seq:
|
|
49
250
|
# easy.perform => true
|
|
@@ -53,13 +254,62 @@ module Curl
|
|
|
53
254
|
# the configured HTTP Verb.
|
|
54
255
|
#
|
|
55
256
|
def perform
|
|
56
|
-
|
|
57
|
-
self.
|
|
58
|
-
|
|
257
|
+
Curl.__send__(:apply_safety!, self) if Curl.respond_to?(:apply_safety!, true)
|
|
258
|
+
self.class.flush_deferred_multi_closes
|
|
259
|
+
|
|
260
|
+
if Curl.scheduler_active? && self.multi.nil?
|
|
261
|
+
ret = Curl.perform_with_scheduler(self)
|
|
262
|
+
else
|
|
263
|
+
multi = self.multi
|
|
264
|
+
created_multi = multi.nil?
|
|
265
|
+
raised = false
|
|
266
|
+
|
|
267
|
+
if created_multi
|
|
268
|
+
multi = Curl::Multi.new
|
|
269
|
+
self.multi = multi
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
begin
|
|
273
|
+
multi.add(self)
|
|
274
|
+
ret = multi.perform
|
|
275
|
+
multi.remove(self) if self.multi == multi
|
|
276
|
+
rescue Exception
|
|
277
|
+
raised = true
|
|
278
|
+
raise
|
|
279
|
+
ensure
|
|
280
|
+
if created_multi
|
|
281
|
+
if raised
|
|
282
|
+
unless self.class.release_deferred_multi_close(multi, self)
|
|
283
|
+
self.class.defer_multi_close(multi, self)
|
|
284
|
+
end
|
|
285
|
+
self.multi = nil if self.multi == multi
|
|
286
|
+
elsif Curl::Multi.autoclose
|
|
287
|
+
multi.__send__(:_autoclose)
|
|
288
|
+
self.multi = nil if self.multi == multi
|
|
289
|
+
else
|
|
290
|
+
self.multi = multi
|
|
291
|
+
end
|
|
292
|
+
elsif Curl::Multi.autoclose
|
|
293
|
+
multi.__send__(:_autoclose)
|
|
294
|
+
self.multi = nil if self.multi == multi
|
|
295
|
+
else
|
|
296
|
+
self.multi = multi
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
if (callback_error = _take_callback_error)
|
|
302
|
+
raise callback_error
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
if respond_to?(:unsafe_destination_error) && (unsafe_destination_error = self.unsafe_destination_error)
|
|
306
|
+
raise Curl::Err::UnsafeDestinationError, unsafe_destination_error
|
|
307
|
+
end
|
|
59
308
|
|
|
60
309
|
if self.last_result != 0 && self.on_failure.nil?
|
|
61
|
-
|
|
62
|
-
|
|
310
|
+
err_class, err_summary = Curl::Easy.error(self.last_result)
|
|
311
|
+
err_detail = self.last_error
|
|
312
|
+
raise err_class.new([err_summary, err_detail].compact.join(": "))
|
|
63
313
|
end
|
|
64
314
|
|
|
65
315
|
ret
|
|
@@ -67,6 +317,7 @@ module Curl
|
|
|
67
317
|
|
|
68
318
|
#
|
|
69
319
|
# call-seq:
|
|
320
|
+
|
|
70
321
|
#
|
|
71
322
|
# easy = Curl::Easy.new
|
|
72
323
|
# easy.nosignal = true
|
|
@@ -83,54 +334,59 @@ module Curl
|
|
|
83
334
|
# easy.perform
|
|
84
335
|
#
|
|
85
336
|
def delete=(onoff)
|
|
86
|
-
set :customrequest, onoff ? '
|
|
337
|
+
set :customrequest, onoff ? 'DELETE' : nil
|
|
87
338
|
onoff
|
|
88
339
|
end
|
|
89
|
-
#
|
|
340
|
+
#
|
|
90
341
|
# call-seq:
|
|
91
|
-
#
|
|
342
|
+
#
|
|
92
343
|
# easy = Curl::Easy.new("url")
|
|
93
|
-
# easy.version = Curl::
|
|
94
|
-
# easy.
|
|
95
|
-
# easy.
|
|
96
|
-
#
|
|
344
|
+
# easy.version = Curl::HTTP_2_0
|
|
345
|
+
# easy.http_version = Curl::HTTP_1_1
|
|
346
|
+
# easy.http_version = Curl::HTTP_1_0
|
|
347
|
+
# easy.http_version = Curl::HTTP_NONE
|
|
348
|
+
#
|
|
97
349
|
def version=(http_version)
|
|
98
|
-
|
|
350
|
+
self.http_version = http_version
|
|
99
351
|
end
|
|
100
352
|
|
|
101
|
-
|
|
353
|
+
def version
|
|
354
|
+
http_version
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
#
|
|
102
358
|
# call-seq:
|
|
103
359
|
# easy.url = "http://some.url/" => "http://some.url/"
|
|
104
|
-
#
|
|
360
|
+
#
|
|
105
361
|
# Set the URL for subsequent calls to +perform+. It is acceptable
|
|
106
362
|
# (and even recommended) to reuse Curl::Easy instances by reassigning
|
|
107
363
|
# the URL between calls to +perform+.
|
|
108
|
-
#
|
|
364
|
+
#
|
|
109
365
|
def url=(u)
|
|
110
366
|
set :url, u
|
|
111
367
|
end
|
|
112
368
|
|
|
113
|
-
#
|
|
369
|
+
#
|
|
114
370
|
# call-seq:
|
|
115
371
|
# easy.proxy_url = string => string
|
|
116
|
-
#
|
|
372
|
+
#
|
|
117
373
|
# Set the URL of the HTTP proxy to use for subsequent calls to +perform+.
|
|
118
374
|
# The URL should specify the the host name or dotted IP address. To specify
|
|
119
375
|
# port number in this string, append :[port] to the end of the host name.
|
|
120
376
|
# The proxy string may be prefixed with [protocol]:// since any such prefix
|
|
121
377
|
# will be ignored. The proxy's port number may optionally be specified with
|
|
122
378
|
# the separate option proxy_port .
|
|
123
|
-
#
|
|
379
|
+
#
|
|
124
380
|
# When you tell the library to use an HTTP proxy, libcurl will transparently
|
|
125
381
|
# convert operations to HTTP even if you specify an FTP URL etc. This may have
|
|
126
382
|
# an impact on what other features of the library you can use, such as
|
|
127
383
|
# FTP specifics that don't work unless you tunnel through the HTTP proxy. Such
|
|
128
384
|
# tunneling is activated with proxy_tunnel = true.
|
|
129
|
-
#
|
|
385
|
+
#
|
|
130
386
|
# libcurl respects the environment variables *http_proxy*, *ftp_proxy*,
|
|
131
387
|
# *all_proxy* etc, if any of those is set. The proxy_url option does however
|
|
132
388
|
# override any possibly set environment variables.
|
|
133
|
-
#
|
|
389
|
+
#
|
|
134
390
|
# Starting with libcurl 7.14.1, the proxy host string given in environment
|
|
135
391
|
# variables can be specified the exact same way as the proxy can be set with
|
|
136
392
|
# proxy_url, including protocol prefix (http://) and embedded user + password.
|
|
@@ -139,99 +395,150 @@ module Curl
|
|
|
139
395
|
set :proxy, url
|
|
140
396
|
end
|
|
141
397
|
|
|
398
|
+
#
|
|
399
|
+
# call-seq:
|
|
400
|
+
# easy.request_target = string => string
|
|
401
|
+
#
|
|
402
|
+
# Set the request-target used in the HTTP request line (libcurl CURLOPT_REQUEST_TARGET).
|
|
403
|
+
# Useful for absolute-form request targets (e.g., when speaking to proxies) or
|
|
404
|
+
# special targets like "*" (OPTIONS *). Requires libcurl with CURLOPT_REQUEST_TARGET support.
|
|
405
|
+
#
|
|
406
|
+
def request_target=(value)
|
|
407
|
+
if Curl.const_defined?(:CURLOPT_REQUEST_TARGET)
|
|
408
|
+
set :request_target, value
|
|
409
|
+
else
|
|
410
|
+
raise NotImplementedError, "CURLOPT_REQUEST_TARGET is not supported by this libcurl"
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
142
414
|
def ssl_verify_host=(value)
|
|
143
415
|
value = 1 if value.class == TrueClass
|
|
144
416
|
value = 0 if value.class == FalseClass
|
|
145
417
|
self.ssl_verify_host_integer=value
|
|
146
418
|
end
|
|
147
419
|
|
|
148
|
-
#
|
|
420
|
+
#
|
|
149
421
|
# call-seq:
|
|
150
422
|
# easy.ssl_verify_host? => boolean
|
|
151
|
-
#
|
|
423
|
+
#
|
|
152
424
|
# Deprecated: call easy.ssl_verify_host instead
|
|
153
425
|
# can be one of [0,1,2]
|
|
154
|
-
#
|
|
426
|
+
#
|
|
155
427
|
# Determine whether this Curl instance will verify that the server cert
|
|
156
428
|
# is for the server it is known as.
|
|
157
|
-
#
|
|
429
|
+
#
|
|
158
430
|
def ssl_verify_host?
|
|
159
431
|
ssl_verify_host.nil? ? false : (ssl_verify_host > 0)
|
|
160
432
|
end
|
|
161
433
|
|
|
162
|
-
#
|
|
434
|
+
#
|
|
163
435
|
# call-seq:
|
|
164
436
|
# easy.interface = string => string
|
|
165
|
-
#
|
|
437
|
+
#
|
|
166
438
|
# Set the interface name to use as the outgoing network interface.
|
|
167
439
|
# The name can be an interface name, an IP address or a host name.
|
|
168
|
-
#
|
|
440
|
+
#
|
|
169
441
|
def interface=(value)
|
|
170
442
|
set :interface, value
|
|
171
443
|
end
|
|
172
444
|
|
|
173
|
-
#
|
|
445
|
+
#
|
|
174
446
|
# call-seq:
|
|
175
447
|
# easy.userpwd = string => string
|
|
176
|
-
#
|
|
448
|
+
#
|
|
177
449
|
# Set the username/password string to use for subsequent calls to +perform+.
|
|
178
450
|
# The supplied string should have the form "username:password"
|
|
179
|
-
#
|
|
451
|
+
#
|
|
180
452
|
def userpwd=(value)
|
|
181
453
|
set :userpwd, value
|
|
182
454
|
end
|
|
183
455
|
|
|
184
|
-
#
|
|
456
|
+
#
|
|
185
457
|
# call-seq:
|
|
186
458
|
# easy.proxypwd = string => string
|
|
187
|
-
#
|
|
459
|
+
#
|
|
188
460
|
# Set the username/password string to use for proxy connection during
|
|
189
461
|
# subsequent calls to +perform+. The supplied string should have the
|
|
190
462
|
# form "username:password"
|
|
191
|
-
#
|
|
463
|
+
#
|
|
192
464
|
def proxypwd=(value)
|
|
193
465
|
set :proxyuserpwd, value
|
|
194
466
|
end
|
|
195
467
|
|
|
196
|
-
#
|
|
468
|
+
#
|
|
197
469
|
# call-seq:
|
|
198
470
|
# easy.cookies = "name1=content1; name2=content2;" => string
|
|
199
|
-
#
|
|
200
|
-
# Set
|
|
201
|
-
# be NAME=CONTENTS, where NAME is the cookie name and
|
|
202
|
-
# Set multiple cookies in one string like this:
|
|
203
|
-
#
|
|
471
|
+
#
|
|
472
|
+
# Set the manual Cookie request header for this Curl::Easy instance.
|
|
473
|
+
# The format of the string should be NAME=CONTENTS, where NAME is the cookie name and
|
|
474
|
+
# CONTENTS is what the cookie should contain. Set multiple cookies in one string like this:
|
|
475
|
+
# "name1=content1; name2=content2;".
|
|
476
|
+
#
|
|
477
|
+
# Notes:
|
|
478
|
+
# - This only affects the outgoing Cookie header (libcurl CURLOPT_COOKIE) and does NOT
|
|
479
|
+
# alter the internal libcurl cookie engine (which stores cookies from Set-Cookie).
|
|
480
|
+
# - To change cookies stored in the engine, use {#cookielist} / {#cookielist=} or
|
|
481
|
+
# {#set} with :cookielist.
|
|
482
|
+
# - To clear a previously set manual Cookie header, assign an empty string ('').
|
|
483
|
+
# Assigning +nil+ has no effect in current curb versions.
|
|
484
|
+
#
|
|
204
485
|
def cookies=(value)
|
|
205
486
|
set :cookie, value
|
|
206
487
|
end
|
|
207
488
|
|
|
208
|
-
#
|
|
489
|
+
#
|
|
209
490
|
# call-seq:
|
|
210
491
|
# easy.cookiefile = string => string
|
|
211
|
-
#
|
|
492
|
+
#
|
|
212
493
|
# Set a file that contains cookies to be sent in subsequent requests by this Curl::Easy instance.
|
|
213
|
-
#
|
|
494
|
+
#
|
|
214
495
|
# *Note* that you must set enable_cookies true to enable the cookie
|
|
215
496
|
# engine, or this option will be ignored.
|
|
216
|
-
#
|
|
497
|
+
#
|
|
498
|
+
# Note: assigning +nil+ has no effect; pass a path string to use a cookie file.
|
|
499
|
+
#
|
|
217
500
|
def cookiefile=(value)
|
|
218
501
|
set :cookiefile, value
|
|
219
502
|
end
|
|
220
503
|
|
|
221
|
-
#
|
|
504
|
+
#
|
|
222
505
|
# call-seq:
|
|
223
506
|
# easy.cookiejar = string => string
|
|
224
|
-
#
|
|
225
|
-
# Set a cookiejar file to use for this Curl::Easy instance.
|
|
226
|
-
#
|
|
227
|
-
#
|
|
507
|
+
#
|
|
508
|
+
# Set a cookiejar file to use for this Curl::Easy instance. Cookies from the response
|
|
509
|
+
# will be written into this file.
|
|
510
|
+
#
|
|
228
511
|
# *Note* that you must set enable_cookies true to enable the cookie
|
|
229
512
|
# engine, or this option will be ignored.
|
|
230
|
-
#
|
|
513
|
+
#
|
|
514
|
+
# Note: assigning +nil+ has no effect; pass a path string to persist cookies to a file.
|
|
515
|
+
#
|
|
231
516
|
def cookiejar=(value)
|
|
232
517
|
set :cookiejar, value
|
|
233
518
|
end
|
|
234
519
|
|
|
520
|
+
#
|
|
521
|
+
# call-seq:
|
|
522
|
+
# easy.cookielist = string => string
|
|
523
|
+
#
|
|
524
|
+
# Modify cookies in libcurl's internal cookie engine (CURLOPT_COOKIELIST).
|
|
525
|
+
# Accepts a Set-Cookie style string, one or more lines in Netscape cookie file format,
|
|
526
|
+
# or one of the special commands: "ALL" (clear), "SESS" (remove session cookies),
|
|
527
|
+
# "FLUSH" (write to jar), "RELOAD" (reload from file).
|
|
528
|
+
#
|
|
529
|
+
# Examples:
|
|
530
|
+
# easy.cookielist = "Set-Cookie: session=42; Domain=example.com; Path=/;"
|
|
531
|
+
# easy.cookielist = [
|
|
532
|
+
# ['.example.com', 'TRUE', '/', 'FALSE', 0, 'c1', 'v1'].join("\t"),
|
|
533
|
+
# ['.example.com', 'TRUE', '/', 'FALSE', 0, 'c2', 'v2'].join("\t"),
|
|
534
|
+
# ''
|
|
535
|
+
# ].join("\n")
|
|
536
|
+
# easy.cookielist = 'ALL' # clear all cookies in the engine
|
|
537
|
+
#
|
|
538
|
+
def cookielist=(value)
|
|
539
|
+
set :cookielist, value
|
|
540
|
+
end
|
|
541
|
+
|
|
235
542
|
#
|
|
236
543
|
# call-seq:
|
|
237
544
|
# easy = Curl::Easy.new("url") do|c|
|
|
@@ -302,7 +609,7 @@ module Curl
|
|
|
302
609
|
|
|
303
610
|
#
|
|
304
611
|
# call-seq:
|
|
305
|
-
# Curl::Easy.perform(url) { |easy| ... } =>
|
|
612
|
+
# Curl::Easy.perform(url) { |easy| ... } => #<Curl::Easy...>
|
|
306
613
|
#
|
|
307
614
|
# Convenience method that creates a new Curl::Easy instance with
|
|
308
615
|
# the specified URL and calls the general +perform+ method, before returning
|
|
@@ -320,7 +627,7 @@ module Curl
|
|
|
320
627
|
|
|
321
628
|
#
|
|
322
629
|
# call-seq:
|
|
323
|
-
# Curl::Easy.http_get(url) { |easy| ... } =>
|
|
630
|
+
# Curl::Easy.http_get(url) { |easy| ... } => #<Curl::Easy...>
|
|
324
631
|
#
|
|
325
632
|
# Convenience method that creates a new Curl::Easy instance with
|
|
326
633
|
# the specified URL and calls +http_get+, before returning the new instance.
|
|
@@ -337,7 +644,7 @@ module Curl
|
|
|
337
644
|
|
|
338
645
|
#
|
|
339
646
|
# call-seq:
|
|
340
|
-
# Curl::Easy.http_head(url) { |easy| ... } =>
|
|
647
|
+
# Curl::Easy.http_head(url) { |easy| ... } => #<Curl::Easy...>
|
|
341
648
|
#
|
|
342
649
|
# Convenience method that creates a new Curl::Easy instance with
|
|
343
650
|
# the specified URL and calls +http_head+, before returning the new instance.
|
|
@@ -355,13 +662,36 @@ module Curl
|
|
|
355
662
|
#
|
|
356
663
|
# call-seq:
|
|
357
664
|
# Curl::Easy.http_put(url, data) {|c| ... }
|
|
665
|
+
# Curl::Easy.http_put(url, "some=urlencoded%20form%20data&and=so%20on") => true
|
|
666
|
+
# Curl::Easy.http_put(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
|
|
667
|
+
# Curl::Easy.http_put(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
|
|
668
|
+
# Curl::Easy.http_put(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
|
|
358
669
|
#
|
|
359
670
|
# see easy.http_put
|
|
360
671
|
#
|
|
361
|
-
def http_put(
|
|
362
|
-
|
|
672
|
+
def http_put(*args)
|
|
673
|
+
url = args.shift
|
|
674
|
+
c = Curl::Easy.new(url)
|
|
675
|
+
yield c if block_given?
|
|
676
|
+
c.http_put(*args)
|
|
677
|
+
c
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
#
|
|
681
|
+
# call-seq:
|
|
682
|
+
# Curl::Easy.http_patch(url, data) {|c| ... }
|
|
683
|
+
# Curl::Easy.http_patch(url, "some=urlencoded%20form%20data&and=so%20on") => true
|
|
684
|
+
# Curl::Easy.http_patch(url, "some=urlencoded%20form%20data", "and=so%20on", ...) => true
|
|
685
|
+
# Curl::Easy.http_patch(url, "some=urlencoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
|
|
686
|
+
# Curl::Easy.http_patch(url, Curl::PostField, Curl::PostField ..., Curl::PostField) => true
|
|
687
|
+
#
|
|
688
|
+
# see easy.http_patch
|
|
689
|
+
#
|
|
690
|
+
def http_patch(*args)
|
|
691
|
+
url = args.shift
|
|
692
|
+
c = Curl::Easy.new(url)
|
|
363
693
|
yield c if block_given?
|
|
364
|
-
c.
|
|
694
|
+
c.http_patch(*args)
|
|
365
695
|
c
|
|
366
696
|
end
|
|
367
697
|
|
|
@@ -391,7 +721,7 @@ module Curl
|
|
|
391
721
|
|
|
392
722
|
#
|
|
393
723
|
# call-seq:
|
|
394
|
-
# Curl::Easy.http_delete(url) { |easy| ... } =>
|
|
724
|
+
# Curl::Easy.http_delete(url) { |easy| ... } => #<Curl::Easy...>
|
|
395
725
|
#
|
|
396
726
|
# Convenience method that creates a new Curl::Easy instance with
|
|
397
727
|
# the specified URL and calls +http_delete+, before returning the new instance.
|
|
@@ -405,35 +735,34 @@ module Curl
|
|
|
405
735
|
c.http_delete
|
|
406
736
|
c
|
|
407
737
|
end
|
|
408
|
-
|
|
738
|
+
|
|
409
739
|
# call-seq:
|
|
410
|
-
# Curl::Easy.download(url, filename =
|
|
411
|
-
#
|
|
740
|
+
# Curl::Easy.download(url, filename = nil, options = {}) { |curl| ... }
|
|
741
|
+
#
|
|
412
742
|
# Stream the specified url (via perform) and save the data directly to the
|
|
413
|
-
# supplied filename
|
|
414
|
-
#
|
|
415
|
-
#
|
|
743
|
+
# supplied filename. The destination is written through a temporary file and
|
|
744
|
+
# existing files are not overwritten unless <tt>:overwrite => true</tt> is
|
|
745
|
+
# passed. When filename is omitted, the destination is safely derived from the
|
|
746
|
+
# last URL path component in the current directory. Pass
|
|
747
|
+
# <tt>:download_dir</tt> to treat the filename as a basename inside a trusted
|
|
748
|
+
# directory and reject absolute, parent-directory, dotfile, and nested names.
|
|
749
|
+
#
|
|
416
750
|
# If a block is supplied, it will be passed the curl instance prior to the
|
|
417
751
|
# perform call.
|
|
418
|
-
#
|
|
752
|
+
#
|
|
419
753
|
# *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
|
|
754
|
+
# download, to account for the automatic routing of data to the specified file: The
|
|
421
755
|
# data string is passed to the handler *before* it is written
|
|
422
|
-
# to the file, allowing the handler to perform mutative operations where
|
|
756
|
+
# to the file, allowing the handler to perform mutative operations where
|
|
423
757
|
# 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
|
|
758
|
+
# returns a size that differs from the data chunk size - in this case, the
|
|
425
759
|
# offending chunk will *not* be written to the file, the file will be closed,
|
|
426
760
|
# and a Curl::Err::AbortedByCallbackError will be raised.
|
|
427
|
-
def download(url, filename =
|
|
761
|
+
def download(url, filename = nil, download_options = {}, &blk)
|
|
428
762
|
curl = Curl::Easy.new(url, &blk)
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
filename
|
|
433
|
-
else
|
|
434
|
-
File.open(filename, 'wb')
|
|
435
|
-
end
|
|
436
|
-
|
|
763
|
+
_download_path, output, safe_output = Curl.prepare_download_output(url, filename, download_options)
|
|
764
|
+
|
|
765
|
+
performed = false
|
|
437
766
|
begin
|
|
438
767
|
old_on_body = curl.on_body do |data|
|
|
439
768
|
result = old_on_body ? old_on_body.call(data) : data.length
|
|
@@ -441,10 +770,15 @@ module Curl
|
|
|
441
770
|
result
|
|
442
771
|
end
|
|
443
772
|
curl.perform
|
|
773
|
+
performed = true
|
|
444
774
|
ensure
|
|
445
|
-
|
|
775
|
+
if safe_output
|
|
776
|
+
output.close(performed)
|
|
777
|
+
else
|
|
778
|
+
output.close rescue IOError
|
|
779
|
+
end
|
|
446
780
|
end
|
|
447
|
-
|
|
781
|
+
|
|
448
782
|
return curl
|
|
449
783
|
end
|
|
450
784
|
end
|