curb 0.7.15 → 0.8.0
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.
- data/README +5 -1
- data/Rakefile +7 -3
- data/ext/curb.c +600 -0
- data/ext/curb.h +5 -5
- data/ext/curb_easy.c +319 -393
- data/ext/curb_easy.h +1 -0
- data/ext/curb_errors.c +10 -0
- data/ext/curb_macros.h +4 -0
- data/ext/curb_multi.c +69 -13
- data/ext/extconf.rb +223 -3
- data/lib/curb.rb +2 -307
- data/lib/curl/easy.rb +385 -0
- data/lib/curl/multi.rb +244 -0
- data/tests/bug_crash_on_debug.rb +39 -0
- data/tests/bug_crash_on_progress.rb +33 -0
- data/tests/helper.rb +8 -0
- data/tests/tc_curl_download.rb +4 -4
- data/tests/tc_curl_easy.rb +110 -10
- data/tests/tc_curl_easy_setopt.rb +31 -0
- metadata +33 -41
data/lib/curl/multi.rb
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
module Curl
|
|
2
|
+
|
|
3
|
+
class Multi
|
|
4
|
+
class << self
|
|
5
|
+
# call-seq:
|
|
6
|
+
# Curl::Multi.get('url1','url2','url3','url4','url5', :follow_location => true) do|easy|
|
|
7
|
+
# easy
|
|
8
|
+
# end
|
|
9
|
+
#
|
|
10
|
+
# Blocking call to fetch multiple url's in parallel.
|
|
11
|
+
def get(urls, easy_options={}, multi_options={}, &blk)
|
|
12
|
+
url_confs = []
|
|
13
|
+
urls.each do|url|
|
|
14
|
+
url_confs << {:url => url, :method => :get}.merge(easy_options)
|
|
15
|
+
end
|
|
16
|
+
self.http(url_confs, multi_options) {|c,code,method| blk.call(c) if blk }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# call-seq:
|
|
20
|
+
#
|
|
21
|
+
# Curl::Multi.post([{:url => 'url1', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
|
|
22
|
+
# {:url => 'url2', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}},
|
|
23
|
+
# {:url => 'url3', :post_fields => {'field1' => 'value1', 'field2' => 'value2'}}],
|
|
24
|
+
# { :follow_location => true, :multipart_form_post => true },
|
|
25
|
+
# {:pipeline => true }) do|easy|
|
|
26
|
+
# easy_handle_on_request_complete
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
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
|
|
32
|
+
# easy_options: are a set of common options to set on all easy handles
|
|
33
|
+
# multi_options: options to set on the Curl::Multi handle
|
|
34
|
+
#
|
|
35
|
+
def post(urls_with_config, easy_options={}, multi_options={}, &blk)
|
|
36
|
+
url_confs = []
|
|
37
|
+
urls_with_config.each do|uconf|
|
|
38
|
+
url_confs << uconf.merge(:method => :post).merge(easy_options)
|
|
39
|
+
end
|
|
40
|
+
self.http(url_confs, multi_options) {|c,code,method| blk.call(c) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# call-seq:
|
|
44
|
+
#
|
|
45
|
+
# Curl::Multi.put([{:url => 'url1', :put_data => "some message"},
|
|
46
|
+
# {:url => 'url2', :put_data => IO.read('filepath')},
|
|
47
|
+
# {:url => 'url3', :put_data => "maybe another string or socket?"],
|
|
48
|
+
# {:follow_location => true},
|
|
49
|
+
# {:pipeline => true }) do|easy|
|
|
50
|
+
# easy_handle_on_request_complete
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
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
|
|
56
|
+
# easy_options: are a set of common options to set on all easy handles
|
|
57
|
+
# multi_options: options to set on the Curl::Multi handle
|
|
58
|
+
#
|
|
59
|
+
def put(urls_with_config, easy_options={}, multi_options={}, &blk)
|
|
60
|
+
url_confs = []
|
|
61
|
+
urls_with_config.each do|uconf|
|
|
62
|
+
url_confs << uconf.merge(:method => :put).merge(easy_options)
|
|
63
|
+
end
|
|
64
|
+
self.http(url_confs, multi_options) {|c,code,method| blk.call(c) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# call-seq:
|
|
69
|
+
#
|
|
70
|
+
# Curl::Multi.http( [
|
|
71
|
+
# { :url => 'url1', :method => :post,
|
|
72
|
+
# :post_fields => {'field1' => 'value1', 'field2' => 'value2'} },
|
|
73
|
+
# { :url => 'url2', :method => :get,
|
|
74
|
+
# :follow_location => true, :max_redirects => 3 },
|
|
75
|
+
# { :url => 'url3', :method => :put, :put_data => File.open('file.txt','rb') },
|
|
76
|
+
# { :url => 'url4', :method => :head }
|
|
77
|
+
# ], {:pipeline => true})
|
|
78
|
+
#
|
|
79
|
+
# Blocking call to issue multiple HTTP requests with varying verb's.
|
|
80
|
+
#
|
|
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
|
|
83
|
+
# blk: a callback, that yeilds when a handle is completed
|
|
84
|
+
#
|
|
85
|
+
def http(urls_with_config, multi_options={}, &blk)
|
|
86
|
+
m = Curl::Multi.new
|
|
87
|
+
|
|
88
|
+
# maintain a sane number of easy handles
|
|
89
|
+
multi_options[:max_connects] = max_connects = multi_options.key?(:max_connects) ? multi_options[:max_connects] : 10
|
|
90
|
+
|
|
91
|
+
free_handles = [] # keep a list of free easy handles
|
|
92
|
+
|
|
93
|
+
# configure the multi handle
|
|
94
|
+
multi_options.each { |k,v| m.send("#{k}=", v) }
|
|
95
|
+
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_body,:on_header]
|
|
96
|
+
|
|
97
|
+
add_free_handle = proc do|conf, easy|
|
|
98
|
+
c = conf.dup # avoid being destructive to input
|
|
99
|
+
url = c.delete(:url)
|
|
100
|
+
method = c.delete(:method)
|
|
101
|
+
headers = c.delete(:headers)
|
|
102
|
+
|
|
103
|
+
easy = Curl::Easy.new if easy.nil?
|
|
104
|
+
|
|
105
|
+
easy.url = url
|
|
106
|
+
|
|
107
|
+
# assign callbacks
|
|
108
|
+
callbacks.each do |cb|
|
|
109
|
+
cbproc = c.delete(cb)
|
|
110
|
+
easy.send(cb,&cbproc) if cbproc
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
case method
|
|
114
|
+
when :post
|
|
115
|
+
fields = c.delete(:post_fields)
|
|
116
|
+
# set the post post using the url fields
|
|
117
|
+
easy.post_body = fields.map{|f,k| "#{easy.escape(f)}=#{easy.escape(k)}"}.join('&')
|
|
118
|
+
when :put
|
|
119
|
+
easy.put_data = c.delete(:put_data)
|
|
120
|
+
when :head
|
|
121
|
+
easy.head = true
|
|
122
|
+
when :delete
|
|
123
|
+
easy.delete = true
|
|
124
|
+
when :get
|
|
125
|
+
else
|
|
126
|
+
# XXX: nil is treated like a GET
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# headers is a special key
|
|
130
|
+
headers.each {|k,v| easy.headers[k] = v } if headers
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# use the remaining options as specific configuration to the easy handle
|
|
134
|
+
# bad options should raise an undefined method error
|
|
135
|
+
#
|
|
136
|
+
c.each { |k,v| easy.send("#{k}=",v) }
|
|
137
|
+
|
|
138
|
+
easy.on_complete {|curl,code|
|
|
139
|
+
free_handles << curl
|
|
140
|
+
blk.call(curl,code,method) if blk
|
|
141
|
+
}
|
|
142
|
+
m.add(easy)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
max_connects.times do
|
|
146
|
+
conf = urls_with_config.pop
|
|
147
|
+
add_free_handle.call conf, nil
|
|
148
|
+
break if urls_with_config.empty?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
consume_free_handles = proc do
|
|
152
|
+
# as we idle consume free handles
|
|
153
|
+
if urls_with_config.size > 0 && free_handles.size > 0
|
|
154
|
+
easy = free_handles.pop
|
|
155
|
+
conf = urls_with_config.pop
|
|
156
|
+
add_free_handle.call conf, easy
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
until urls_with_config.empty?
|
|
161
|
+
m.perform do
|
|
162
|
+
consume_free_handles.call
|
|
163
|
+
end
|
|
164
|
+
consume_free_handles.call
|
|
165
|
+
end
|
|
166
|
+
free_handles = nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# call-seq:
|
|
170
|
+
#
|
|
171
|
+
# Curl::Multi.download(['http://example.com/p/a/t/h/file1.txt','http://example.com/p/a/t/h/file2.txt']){|c|}
|
|
172
|
+
#
|
|
173
|
+
# will create 2 new files file1.txt and file2.txt
|
|
174
|
+
#
|
|
175
|
+
# 2 files will be opened, and remain open until the call completes
|
|
176
|
+
#
|
|
177
|
+
# when using the :post or :put method, urls should be a hash, including the individual post fields per post
|
|
178
|
+
#
|
|
179
|
+
def download(urls,easy_options={},multi_options={},download_paths=nil,&blk)
|
|
180
|
+
errors = []
|
|
181
|
+
procs = []
|
|
182
|
+
files = []
|
|
183
|
+
urls_with_config = []
|
|
184
|
+
url_to_download_paths = {}
|
|
185
|
+
|
|
186
|
+
urls.each_with_index do|urlcfg,i|
|
|
187
|
+
if urlcfg.is_a?(Hash)
|
|
188
|
+
url = url[:url]
|
|
189
|
+
else
|
|
190
|
+
url = urlcfg
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
if download_paths and download_paths[i]
|
|
194
|
+
download_path = download_paths[i]
|
|
195
|
+
else
|
|
196
|
+
download_path = File.basename(url)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
file = lambda do|dp|
|
|
200
|
+
file = File.open(dp,"wb")
|
|
201
|
+
procs << (lambda {|data| file.write data; data.size })
|
|
202
|
+
files << file
|
|
203
|
+
file
|
|
204
|
+
end.call(download_path)
|
|
205
|
+
|
|
206
|
+
if urlcfg.is_a?(Hash)
|
|
207
|
+
urls_with_config << urlcfg.merge({:on_body => procs.last}.merge(easy_options))
|
|
208
|
+
else
|
|
209
|
+
urls_with_config << {:url => url, :on_body => procs.last, :method => :get}.merge(easy_options)
|
|
210
|
+
end
|
|
211
|
+
url_to_download_paths[url] = {:path => download_path, :file => file} # store for later
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if blk
|
|
215
|
+
# when injecting the block, ensure file is closed before yielding
|
|
216
|
+
Curl::Multi.http(urls_with_config, multi_options) do |c,code,method|
|
|
217
|
+
info = url_to_download_paths[c.url]
|
|
218
|
+
begin
|
|
219
|
+
file = info[:file]
|
|
220
|
+
files.reject!{|f| f == file }
|
|
221
|
+
file.close
|
|
222
|
+
rescue => e
|
|
223
|
+
errors << e
|
|
224
|
+
end
|
|
225
|
+
blk.call(c,info[:path])
|
|
226
|
+
end
|
|
227
|
+
else
|
|
228
|
+
Curl::Multi.http(urls_with_config, multi_options)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
ensure
|
|
232
|
+
files.each {|f|
|
|
233
|
+
begin
|
|
234
|
+
f.close
|
|
235
|
+
rescue => e
|
|
236
|
+
errors << e
|
|
237
|
+
end
|
|
238
|
+
}
|
|
239
|
+
raise errors unless errors.empty?
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
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
|
+
class BugCrashOnDebug < Test::Unit::TestCase
|
|
10
|
+
|
|
11
|
+
def test_on_debug
|
|
12
|
+
server = WEBrick::HTTPServer.new( :Port => 9999 )
|
|
13
|
+
server.mount_proc("/test") do|req,res|
|
|
14
|
+
res.body = "hi"
|
|
15
|
+
res['Content-Type'] = "text/html"
|
|
16
|
+
end
|
|
17
|
+
puts 'a'
|
|
18
|
+
thread = Thread.new(server) do|srv|
|
|
19
|
+
srv.start
|
|
20
|
+
end
|
|
21
|
+
puts 'b'
|
|
22
|
+
c = Curl::Easy.new('http://localhost:9999/test')
|
|
23
|
+
c.on_debug do|x|
|
|
24
|
+
puts x.inspect
|
|
25
|
+
raise "error" # this will get swallowed
|
|
26
|
+
end
|
|
27
|
+
c.perform
|
|
28
|
+
puts 'c'
|
|
29
|
+
ensure
|
|
30
|
+
puts 'd'
|
|
31
|
+
server.shutdown
|
|
32
|
+
puts 'e'
|
|
33
|
+
puts thread.exit
|
|
34
|
+
puts 'f'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#test_on_debug
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
|
|
6
|
+
class BugCrashOnDebug < Test::Unit::TestCase
|
|
7
|
+
|
|
8
|
+
def test_on_debug
|
|
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
|
|
14
|
+
|
|
15
|
+
thread = Thread.new(server) do|srv|
|
|
16
|
+
srv.start
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
c = Curl::Easy.new('http://localhost:9999/test')
|
|
20
|
+
c.on_progress do|x|
|
|
21
|
+
raise "error"
|
|
22
|
+
end
|
|
23
|
+
c.perform
|
|
24
|
+
|
|
25
|
+
assert false, "should not reach this point"
|
|
26
|
+
|
|
27
|
+
rescue => e
|
|
28
|
+
assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
|
|
29
|
+
c.close
|
|
30
|
+
ensure
|
|
31
|
+
server.shutdown
|
|
32
|
+
end
|
|
33
|
+
end
|
data/tests/helper.rb
CHANGED
|
@@ -65,6 +65,14 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def do_GET(req,res)
|
|
68
|
+
if req.path.match /redirect$/
|
|
69
|
+
res.status = 302
|
|
70
|
+
res['Location'] = '/foo'
|
|
71
|
+
elsif req.path.match /not_here$/
|
|
72
|
+
res.status = 404
|
|
73
|
+
elsif req.path.match /error$/
|
|
74
|
+
res.status = 500
|
|
75
|
+
end
|
|
68
76
|
respond_with(:GET,req,res)
|
|
69
77
|
end
|
|
70
78
|
|
data/tests/tc_curl_download.rb
CHANGED
|
@@ -8,7 +8,7 @@ class TestCurbCurlDownload < Test::Unit::TestCase
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def test_download_url_to_file_via_string
|
|
11
|
-
dl_url = "http://
|
|
11
|
+
dl_url = "http://localhost:9129/ext/curb_easy.c"
|
|
12
12
|
dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
|
|
13
13
|
|
|
14
14
|
curb = Curl::Easy.download(dl_url, dl_path)
|
|
@@ -19,7 +19,7 @@ class TestCurbCurlDownload < Test::Unit::TestCase
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def test_download_url_to_file_via_file_io
|
|
22
|
-
dl_url = "http://
|
|
22
|
+
dl_url = "http://localhost:9129/ext/curb_easy.c"
|
|
23
23
|
dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
|
|
24
24
|
io = File.open(dl_path, 'wb')
|
|
25
25
|
|
|
@@ -32,7 +32,7 @@ class TestCurbCurlDownload < Test::Unit::TestCase
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def test_download_url_to_file_via_io
|
|
35
|
-
dl_url = "http://
|
|
35
|
+
dl_url = "http://localhost:9129/ext/curb_easy.c"
|
|
36
36
|
dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
|
|
37
37
|
reader, writer = IO.pipe
|
|
38
38
|
|
|
@@ -62,7 +62,7 @@ class TestCurbCurlDownload < Test::Unit::TestCase
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def test_download_bad_url_gives_404
|
|
65
|
-
dl_url = "http://
|
|
65
|
+
dl_url = "http://localhost:9129/this_file_does_not_exist.html"
|
|
66
66
|
dl_path = File.join(Dir::tmpdir, "dl_url_test.file")
|
|
67
67
|
|
|
68
68
|
curb = Curl::Easy.download(dl_url, dl_path)
|
data/tests/tc_curl_easy.rb
CHANGED
|
@@ -461,7 +461,8 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
461
461
|
def test_ssl_verify_host
|
|
462
462
|
c = Curl::Easy.new
|
|
463
463
|
assert c.ssl_verify_host?
|
|
464
|
-
|
|
464
|
+
c.ssl_verify_host = 0
|
|
465
|
+
c.ssl_verify_host = false
|
|
465
466
|
assert !c.ssl_verify_host?
|
|
466
467
|
end
|
|
467
468
|
|
|
@@ -507,6 +508,17 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
507
508
|
assert c.ignore_content_length?
|
|
508
509
|
end
|
|
509
510
|
|
|
511
|
+
def test_resolve_mode
|
|
512
|
+
c = Curl::Easy.new
|
|
513
|
+
assert_equal :auto, c.resolve_mode
|
|
514
|
+
c.resolve_mode = :ipv4
|
|
515
|
+
assert_equal :ipv4, c.resolve_mode
|
|
516
|
+
c.resolve_mode = :ipv6
|
|
517
|
+
assert_equal :ipv6, c.resolve_mode
|
|
518
|
+
|
|
519
|
+
assert_raises(ArgumentError) { c.resolve_mode = :bad }
|
|
520
|
+
end
|
|
521
|
+
|
|
510
522
|
def test_enable_cookies
|
|
511
523
|
c = Curl::Easy.new
|
|
512
524
|
assert !c.enable_cookies?
|
|
@@ -549,13 +561,34 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
549
561
|
end
|
|
550
562
|
|
|
551
563
|
def test_on_success_with_on_failure
|
|
552
|
-
curl = Curl::Easy.new(
|
|
564
|
+
curl = Curl::Easy.new(TestServlet.url + '/error')
|
|
553
565
|
on_failure_called = false
|
|
554
566
|
curl.on_success {|c| } # make sure we get the failure call even though this handler is defined
|
|
555
567
|
curl.on_failure {|c,code| on_failure_called = true }
|
|
556
568
|
curl.perform
|
|
569
|
+
assert_equal 500, curl.response_code
|
|
557
570
|
assert on_failure_called, "Failure handler not called"
|
|
558
571
|
end
|
|
572
|
+
|
|
573
|
+
def test_on_success_with_on_missing
|
|
574
|
+
curl = Curl::Easy.new(TestServlet.url + '/not_here')
|
|
575
|
+
on_missing_called = false
|
|
576
|
+
curl.on_success {|c| } # make sure we get the missing call even though this handler is defined
|
|
577
|
+
curl.on_missing {|c,code| on_missing_called = true }
|
|
578
|
+
curl.perform
|
|
579
|
+
assert_equal 404, curl.response_code
|
|
580
|
+
assert on_missing_called, "Missing handler not called"
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
def test_on_success_with_on_redirect
|
|
584
|
+
curl = Curl::Easy.new(TestServlet.url + '/redirect')
|
|
585
|
+
on_redirect_called = false
|
|
586
|
+
curl.on_success {|c| } # make sure we get the redirect call even though this handler is defined
|
|
587
|
+
curl.on_redirect {|c,code| on_redirect_called = true }
|
|
588
|
+
curl.perform
|
|
589
|
+
assert_equal 302, curl.response_code
|
|
590
|
+
assert on_redirect_called, "Redirect handler not called"
|
|
591
|
+
end
|
|
559
592
|
|
|
560
593
|
def test_get_remote
|
|
561
594
|
curl = Curl::Easy.new(TestServlet.url)
|
|
@@ -572,15 +605,35 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
572
605
|
def test_post_remote_is_easy_handle
|
|
573
606
|
# see: http://pastie.org/560852 and
|
|
574
607
|
# http://groups.google.com/group/curb---ruby-libcurl-bindings/browse_thread/thread/216bb2d9b037f347?hl=en
|
|
575
|
-
[:post, :get
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
count
|
|
579
|
-
|
|
608
|
+
[:post, :get, :head, :delete].each do |method|
|
|
609
|
+
retries = 0
|
|
610
|
+
begin
|
|
611
|
+
count = 0
|
|
612
|
+
curl = Curl::Easy.send("http_#{method}", TestServlet.url) do|c|
|
|
613
|
+
count += 1
|
|
614
|
+
assert_equal Curl::Easy, c.class
|
|
615
|
+
end
|
|
616
|
+
assert_equal 1, count, "For request method: #{method.to_s.upcase}"
|
|
617
|
+
rescue Curl::Err::HostResolutionError => e # travis-ci.org fails to resolve... try again?
|
|
618
|
+
retries+=1
|
|
619
|
+
retry if retries < 3
|
|
620
|
+
raise e
|
|
580
621
|
end
|
|
581
|
-
assert_equal 1, count, "For request method: #{method.to_s.upcase}"
|
|
582
622
|
end
|
|
583
623
|
end
|
|
624
|
+
|
|
625
|
+
# see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
|
|
626
|
+
def test_post_multipart_array_remote
|
|
627
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
628
|
+
curl.multipart_form_post = true
|
|
629
|
+
fields = [
|
|
630
|
+
Curl::PostField.file('foo', File.expand_path(File.join(File.dirname(__FILE__),'..','README'))),
|
|
631
|
+
Curl::PostField.file('bar', File.expand_path(File.join(File.dirname(__FILE__),'..','README')))
|
|
632
|
+
]
|
|
633
|
+
curl.http_post(fields)
|
|
634
|
+
assert_match /HTTP POST file upload/, curl.body_str
|
|
635
|
+
assert_match /Content-Disposition: form-data/, curl.body_str
|
|
636
|
+
end
|
|
584
637
|
|
|
585
638
|
def test_post_with_body_remote
|
|
586
639
|
curl = Curl::Easy.new(TestServlet.url)
|
|
@@ -664,6 +717,17 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
664
717
|
assert_match /message$/, curl.body_str
|
|
665
718
|
end
|
|
666
719
|
|
|
720
|
+
# https://github.com/taf2/curb/issues/101
|
|
721
|
+
def test_put_data_null_bytes
|
|
722
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
723
|
+
curl.put_data = "a\0b"
|
|
724
|
+
|
|
725
|
+
curl.perform
|
|
726
|
+
|
|
727
|
+
assert_match /^PUT/, curl.body_str
|
|
728
|
+
assert_match "a\0b", curl.body_str
|
|
729
|
+
end
|
|
730
|
+
|
|
667
731
|
def test_put_nil_data_no_crash
|
|
668
732
|
curl = Curl::Easy.new(TestServlet.url)
|
|
669
733
|
curl.put_data = nil
|
|
@@ -673,7 +737,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
673
737
|
|
|
674
738
|
def test_put_remote_file
|
|
675
739
|
curl = Curl::Easy.new(TestServlet.url)
|
|
676
|
-
File.open(__FILE__,'
|
|
740
|
+
File.open(__FILE__,'rb') do|f|
|
|
677
741
|
assert curl.http_put(f)
|
|
678
742
|
end
|
|
679
743
|
assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str
|
|
@@ -700,7 +764,9 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
700
764
|
|
|
701
765
|
def test_cert_with_password
|
|
702
766
|
curl = Curl::Easy.new(TestServlet.url)
|
|
703
|
-
|
|
767
|
+
path = File.join(File.dirname(__FILE__),"cert.pem")
|
|
768
|
+
curl.certpassword = 'password'
|
|
769
|
+
curl.cert = path
|
|
704
770
|
assert_match /cert.pem$/,curl.cert
|
|
705
771
|
end
|
|
706
772
|
|
|
@@ -888,6 +954,40 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
888
954
|
|
|
889
955
|
end
|
|
890
956
|
|
|
957
|
+
def test_get_set_multi_on_easy
|
|
958
|
+
easy = Curl::Easy.new
|
|
959
|
+
assert_nil easy.multi
|
|
960
|
+
multi = Curl::Multi.new
|
|
961
|
+
easy.multi = multi
|
|
962
|
+
assert_not_nil easy.multi
|
|
963
|
+
assert_equal multi, easy.multi
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
def test_raise_on_progress
|
|
967
|
+
c = Curl::Easy.new($TEST_URL)
|
|
968
|
+
c.on_progress {|w,x,y,z| raise "error" }
|
|
969
|
+
c.perform
|
|
970
|
+
rescue => e
|
|
971
|
+
assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
|
|
972
|
+
c.close
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
def test_raise_on_success
|
|
976
|
+
c = Curl::Easy.new($TEST_URL)
|
|
977
|
+
c.on_success {|x| raise "error" }
|
|
978
|
+
c.perform
|
|
979
|
+
rescue => e
|
|
980
|
+
assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
|
|
981
|
+
c.close
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
def test_raise_on_debug
|
|
985
|
+
c = Curl::Easy.new($TEST_URL)
|
|
986
|
+
c.on_debug { raise "error" }
|
|
987
|
+
c.perform
|
|
988
|
+
assert true, "raise in on debug has no effect"
|
|
989
|
+
end
|
|
990
|
+
|
|
891
991
|
include TestServerMethods
|
|
892
992
|
|
|
893
993
|
def setup
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
|
|
3
|
+
class TestCurbCurlEasySetOpt < Test::Unit::TestCase
|
|
4
|
+
def setup
|
|
5
|
+
@easy = Curl::Easy.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_opt_verbose
|
|
9
|
+
@easy.set :verbose, true
|
|
10
|
+
assert @easy.verbose?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_opt_header
|
|
14
|
+
@easy.set :header, true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_opt_noprogress
|
|
18
|
+
@easy.set :noprogress, true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_opt_nosignal
|
|
22
|
+
@easy.set :nosignal, true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_opt_url
|
|
26
|
+
url = "http://google.com/"
|
|
27
|
+
@easy.set :url, url
|
|
28
|
+
assert_equal url, @easy.url
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|