curb 0.1.4 → 0.7.15
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 +131 -60
- data/Rakefile +81 -68
- data/doc.rb +1 -1
- data/ext/curb.c +107 -70
- data/ext/curb.h +23 -10
- data/ext/curb_easy.c +2156 -908
- data/ext/curb_easy.h +41 -28
- data/ext/curb_errors.c +258 -92
- data/ext/curb_errors.h +25 -2
- data/ext/curb_macros.h +41 -0
- data/ext/curb_multi.c +565 -0
- data/ext/curb_multi.h +26 -0
- data/ext/curb_postfield.c +68 -44
- data/ext/curb_upload.c +80 -0
- data/ext/curb_upload.h +30 -0
- data/ext/extconf.rb +159 -7
- data/lib/curb.rb +308 -0
- data/{ext → lib}/curl.rb +0 -1
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +52 -0
- data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
- data/tests/bug_instance_post_differs_from_class_post.rb +1 -1
- data/tests/bug_multi_segfault.rb +14 -0
- data/tests/bug_postfields_crash.rb +26 -0
- data/tests/bug_postfields_crash2.rb +57 -0
- data/tests/bugtests.rb +9 -0
- data/tests/helper.rb +168 -0
- data/tests/mem_check.rb +65 -0
- data/tests/require_last_or_segfault_script.rb +2 -2
- data/tests/tc_curl_download.rb +75 -0
- data/tests/tc_curl_easy.rb +464 -9
- data/tests/tc_curl_multi.rb +466 -0
- data/tests/tc_curl_postfield.rb +4 -2
- data/tests/timeout.rb +100 -0
- data/tests/timeout_server.rb +33 -0
- metadata +103 -56
- data/ext/curb.rb +0 -46
- data/samples/gmail.rb +0 -48
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
|
|
3
|
+
class TestCurbCurlMulti < Test::Unit::TestCase
|
|
4
|
+
def teardown
|
|
5
|
+
# get a better read on memory loss when running in valgrind
|
|
6
|
+
ObjectSpace.garbage_collect
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_new_multi_01
|
|
10
|
+
d1 = ""
|
|
11
|
+
c1 = Curl::Easy.new($TEST_URL) do |curl|
|
|
12
|
+
curl.headers["User-Agent"] = "myapp-0.0"
|
|
13
|
+
curl.on_body {|d| d1 << d; d.length }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
d2 = ""
|
|
17
|
+
c2 = Curl::Easy.new($TEST_URL) do |curl|
|
|
18
|
+
curl.headers["User-Agent"] = "myapp-0.0"
|
|
19
|
+
curl.on_body {|d| d2 << d; d.length }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
m = Curl::Multi.new
|
|
23
|
+
|
|
24
|
+
m.add( c1 )
|
|
25
|
+
m.add( c2 )
|
|
26
|
+
|
|
27
|
+
m.perform
|
|
28
|
+
|
|
29
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, d1)
|
|
30
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, d2)
|
|
31
|
+
|
|
32
|
+
m = nil
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_perform_block
|
|
37
|
+
c1 = Curl::Easy.new($TEST_URL)
|
|
38
|
+
c2 = Curl::Easy.new($TEST_URL)
|
|
39
|
+
|
|
40
|
+
m = Curl::Multi.new
|
|
41
|
+
|
|
42
|
+
m.add( c1 )
|
|
43
|
+
m.add( c2 )
|
|
44
|
+
|
|
45
|
+
m.perform do
|
|
46
|
+
# idle
|
|
47
|
+
#puts "idling..."
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c1.body_str)
|
|
51
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c2.body_str)
|
|
52
|
+
|
|
53
|
+
m = nil
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# NOTE: if this test runs slowly on Mac OSX, it is probably due to the use of a port install curl+ssl+ares install
|
|
58
|
+
# on my MacBook, this causes curl_easy_init to take nearly 0.01 seconds / * 100 below is 1 second too many!
|
|
59
|
+
def test_n_requests
|
|
60
|
+
n = 100
|
|
61
|
+
m = Curl::Multi.new
|
|
62
|
+
responses = []
|
|
63
|
+
n.times do|i|
|
|
64
|
+
responses[i] = ""
|
|
65
|
+
c = Curl::Easy.new($TEST_URL) do|curl|
|
|
66
|
+
curl.on_body{|data| responses[i] << data; data.size }
|
|
67
|
+
end
|
|
68
|
+
m.add c
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
m.perform
|
|
72
|
+
|
|
73
|
+
assert_equal n, responses.size
|
|
74
|
+
n.times do|i|
|
|
75
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, responses[i], "response #{i}")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
m = nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_n_requests_with_break
|
|
82
|
+
# process n requests then load the handle again and run it again
|
|
83
|
+
n = 2
|
|
84
|
+
m = Curl::Multi.new
|
|
85
|
+
5.times do|it|
|
|
86
|
+
responses = []
|
|
87
|
+
n.times do|i|
|
|
88
|
+
responses[i] = ""
|
|
89
|
+
c = Curl::Easy.new($TEST_URL) do|curl|
|
|
90
|
+
curl.on_body{|data| responses[i] << data; data.size }
|
|
91
|
+
end
|
|
92
|
+
m.add c
|
|
93
|
+
end
|
|
94
|
+
m.perform
|
|
95
|
+
|
|
96
|
+
assert_equal n, responses.size
|
|
97
|
+
n.times do|i|
|
|
98
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, responses[i], "response #{i}")
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
m = nil
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_idle_check
|
|
107
|
+
m = Curl::Multi.new
|
|
108
|
+
e = Curl::Easy.new($TEST_URL)
|
|
109
|
+
|
|
110
|
+
assert(m.idle?, 'A new Curl::Multi handle should be idle')
|
|
111
|
+
|
|
112
|
+
m.add(e)
|
|
113
|
+
|
|
114
|
+
assert((not m.idle?), 'A Curl::Multi handle with a request should not be idle')
|
|
115
|
+
|
|
116
|
+
m.perform
|
|
117
|
+
|
|
118
|
+
assert(m.idle?, 'A Curl::Multi handle should be idle after performing its requests')
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_requests
|
|
122
|
+
m = Curl::Multi.new
|
|
123
|
+
|
|
124
|
+
assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests')
|
|
125
|
+
|
|
126
|
+
10.times do
|
|
127
|
+
m.add(Curl::Easy.new($TEST_URL))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
assert_equal(10, m.requests.length, 'multi.requests should contain all the active requests')
|
|
131
|
+
|
|
132
|
+
m.perform
|
|
133
|
+
|
|
134
|
+
assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests after a perform')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def test_cancel
|
|
138
|
+
m = Curl::Multi.new
|
|
139
|
+
m.cancel! # shouldn't raise anything
|
|
140
|
+
|
|
141
|
+
10.times do
|
|
142
|
+
m.add(Curl::Easy.new($TEST_URL))
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
m.cancel!
|
|
146
|
+
|
|
147
|
+
assert_equal([], m.requests, 'A new Curl::Multi handle should have no requests after being canceled')
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_with_success
|
|
151
|
+
c1 = Curl::Easy.new($TEST_URL)
|
|
152
|
+
c2 = Curl::Easy.new($TEST_URL)
|
|
153
|
+
success_called1 = false
|
|
154
|
+
success_called2 = false
|
|
155
|
+
|
|
156
|
+
c1.on_success do|c|
|
|
157
|
+
success_called1 = true
|
|
158
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
c2.on_success do|c|
|
|
162
|
+
success_called2 = true
|
|
163
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
m = Curl::Multi.new
|
|
167
|
+
|
|
168
|
+
m.add( c1 )
|
|
169
|
+
m.add( c2 )
|
|
170
|
+
|
|
171
|
+
m.perform do
|
|
172
|
+
# idle
|
|
173
|
+
#puts "idling..."
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
assert success_called2
|
|
177
|
+
assert success_called1
|
|
178
|
+
|
|
179
|
+
m = nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def test_with_success_cb_with_404
|
|
183
|
+
c1 = Curl::Easy.new("#{$TEST_URL.gsub(/file:\/\//,'')}/not_here")
|
|
184
|
+
c2 = Curl::Easy.new($TEST_URL)
|
|
185
|
+
success_called1 = false
|
|
186
|
+
success_called2 = false
|
|
187
|
+
|
|
188
|
+
c1.on_success do|c|
|
|
189
|
+
success_called1 = true
|
|
190
|
+
#puts "success 1 called: #{c.body_str.inspect}"
|
|
191
|
+
#assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
c1.on_failure do|c,rc|
|
|
195
|
+
# rc => [Curl::Err::MalformedURLError, "URL using bad/illegal format or missing URL"]
|
|
196
|
+
assert_equal Curl::Easy, c.class
|
|
197
|
+
assert_equal Curl::Err::MalformedURLError, rc.first
|
|
198
|
+
assert_equal "URL using bad/illegal format or missing URL", rc.last
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
c2.on_success do|c|
|
|
202
|
+
# puts "success 2 called: #{c.body_str.inspect}"
|
|
203
|
+
success_called2 = true
|
|
204
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
m = Curl::Multi.new
|
|
208
|
+
|
|
209
|
+
#puts "c1: #{c1.url}"
|
|
210
|
+
m.add( c1 )
|
|
211
|
+
#puts "c2: #{c2.url}"
|
|
212
|
+
m.add( c2 )
|
|
213
|
+
|
|
214
|
+
#puts "calling"
|
|
215
|
+
m.perform do
|
|
216
|
+
# idle
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
assert success_called2
|
|
220
|
+
assert !success_called1
|
|
221
|
+
|
|
222
|
+
m = nil
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# This tests whether, ruby's GC will trash an out of scope easy handle
|
|
226
|
+
class TestForScope
|
|
227
|
+
attr_reader :buf
|
|
228
|
+
|
|
229
|
+
def t_method
|
|
230
|
+
@buf = ""
|
|
231
|
+
@m = Curl::Multi.new
|
|
232
|
+
10.times do|i|
|
|
233
|
+
c = Curl::Easy.new($TEST_URL)
|
|
234
|
+
c.on_success{|b| @buf << b.body_str }
|
|
235
|
+
ObjectSpace.garbage_collect
|
|
236
|
+
@m.add(c)
|
|
237
|
+
ObjectSpace.garbage_collect
|
|
238
|
+
end
|
|
239
|
+
ObjectSpace.garbage_collect
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def t_call
|
|
243
|
+
@m.perform do
|
|
244
|
+
ObjectSpace.garbage_collect
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def self.test
|
|
249
|
+
ObjectSpace.garbage_collect
|
|
250
|
+
tfs = TestForScope.new
|
|
251
|
+
ObjectSpace.garbage_collect
|
|
252
|
+
tfs.t_method
|
|
253
|
+
ObjectSpace.garbage_collect
|
|
254
|
+
tfs.t_call
|
|
255
|
+
ObjectSpace.garbage_collect
|
|
256
|
+
|
|
257
|
+
tfs.buf
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def test_with_garbage_collect
|
|
263
|
+
ObjectSpace.garbage_collect
|
|
264
|
+
buf = TestForScope.test
|
|
265
|
+
ObjectSpace.garbage_collect
|
|
266
|
+
assert_match(/^# DO NOT REMOVE THIS COMMENT/, buf)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
=begin
|
|
270
|
+
def test_remote_requests
|
|
271
|
+
responses = {}
|
|
272
|
+
requests = ["http://google.co.uk/", "http://ruby-lang.org/"]
|
|
273
|
+
m = Curl::Multi.new
|
|
274
|
+
# add a few easy handles
|
|
275
|
+
requests.each do |url|
|
|
276
|
+
responses[url] = ""
|
|
277
|
+
responses["#{url}-header"] = ""
|
|
278
|
+
c = Curl::Easy.new(url) do|curl|
|
|
279
|
+
curl.follow_location = true
|
|
280
|
+
curl.on_header{|data| responses["#{url}-header"] << data; data.size }
|
|
281
|
+
curl.on_body{|data| responses[url] << data; data.size }
|
|
282
|
+
curl.on_success {
|
|
283
|
+
puts curl.last_effective_url
|
|
284
|
+
}
|
|
285
|
+
end
|
|
286
|
+
m.add(c)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
m.perform
|
|
290
|
+
|
|
291
|
+
requests.each do|url|
|
|
292
|
+
puts responses["#{url}-header"].split("\r\n").inspect
|
|
293
|
+
#puts responses[url].size
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
=end
|
|
297
|
+
|
|
298
|
+
def test_multi_easy_get_01
|
|
299
|
+
urls = []
|
|
300
|
+
root_uri = 'http://127.0.0.1:9129/ext/'
|
|
301
|
+
# send a request to fetch all c files in the ext dir
|
|
302
|
+
Dir[File.dirname(__FILE__) + "/../ext/*.c"].each do|path|
|
|
303
|
+
urls << root_uri + File.basename(path)
|
|
304
|
+
end
|
|
305
|
+
urls = urls[0..(urls.size/2)] # keep it fast, webrick...
|
|
306
|
+
Curl::Multi.get(urls, {:follow_location => true}, {:pipeline => true}) do|curl|
|
|
307
|
+
assert_equal 200, curl.response_code
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def test_multi_easy_download_01
|
|
312
|
+
# test collecting response buffers to file e.g. on_body
|
|
313
|
+
root_uri = 'http://127.0.0.1:9129/ext/'
|
|
314
|
+
urls = []
|
|
315
|
+
downloads = []
|
|
316
|
+
file_info = {}
|
|
317
|
+
FileUtils.mkdir("tmp/")
|
|
318
|
+
|
|
319
|
+
# for each file store the size by file name
|
|
320
|
+
Dir[File.dirname(__FILE__) + "/../ext/*.c"].each do|path|
|
|
321
|
+
urls << (root_uri + File.basename(path))
|
|
322
|
+
downloads << "tmp/" + File.basename(path)
|
|
323
|
+
file_info[File.basename(path)] = {:size => File.size(path), :path => path}
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# start downloads
|
|
327
|
+
Curl::Multi.download(urls,{},{},downloads) do|curl,download_path|
|
|
328
|
+
assert_equal 200, curl.response_code
|
|
329
|
+
assert File.exist?(download_path)
|
|
330
|
+
store = file_info[File.basename(download_path)]
|
|
331
|
+
assert_equal file_info[File.basename(download_path)][:size], File.size(download_path), "incomplete download: #{download_path}"
|
|
332
|
+
end
|
|
333
|
+
ensure
|
|
334
|
+
FileUtils.rm_rf("tmp/")
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def test_multi_easy_post_01
|
|
338
|
+
urls = [
|
|
339
|
+
{ :url => TestServlet.url + '?q=1', :post_fields => {'field1' => 'value1', 'k' => 'j'}},
|
|
340
|
+
{ :url => TestServlet.url + '?q=2', :post_fields => {'field2' => 'value2', 'foo' => 'bar', 'i' => 'j' }},
|
|
341
|
+
{ :url => TestServlet.url + '?q=3', :post_fields => {'field3' => 'value3', 'field4' => 'value4'}}
|
|
342
|
+
]
|
|
343
|
+
Curl::Multi.post(urls, {:follow_location => true, :multipart_form_post => true}, {:pipeline => true}) do|easy|
|
|
344
|
+
str = easy.body_str
|
|
345
|
+
assert_match /POST/, str
|
|
346
|
+
fields = {}
|
|
347
|
+
str.gsub(/POST\n/,'').split('&').map{|sv| k, v = sv.split('='); fields[k] = v }
|
|
348
|
+
expected = urls.find{|s| s[:url] == easy.last_effective_url }
|
|
349
|
+
assert_equal expected[:post_fields], fields
|
|
350
|
+
#puts "#{easy.last_effective_url} #{fields.inspect}"
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def test_multi_easy_put_01
|
|
355
|
+
urls = [{ :url => TestServlet.url, :method => :put, :put_data => "message",
|
|
356
|
+
:headers => {'Content-Type' => 'application/json' } },
|
|
357
|
+
{ :url => TestServlet.url, :method => :put, :put_data => "message",
|
|
358
|
+
:headers => {'Content-Type' => 'application/json' } }]
|
|
359
|
+
Curl::Multi.put(urls, {}, {:pipeline => true}) do|easy|
|
|
360
|
+
assert_match /PUT/, easy.body_str
|
|
361
|
+
assert_match /message/, easy.body_str
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def test_multi_easy_http_01
|
|
366
|
+
urls = [
|
|
367
|
+
{ :url => TestServlet.url + '?q=1', :method => :post, :post_fields => {'field1' => 'value1', 'k' => 'j'}},
|
|
368
|
+
{ :url => TestServlet.url + '?q=2', :method => :post, :post_fields => {'field2' => 'value2', 'foo' => 'bar', 'i' => 'j' }},
|
|
369
|
+
{ :url => TestServlet.url + '?q=3', :method => :post, :post_fields => {'field3' => 'value3', 'field4' => 'value4'}},
|
|
370
|
+
{ :url => TestServlet.url, :method => :put, :put_data => "message",
|
|
371
|
+
:headers => {'Content-Type' => 'application/json' } },
|
|
372
|
+
{ :url => TestServlet.url, :method => :get }
|
|
373
|
+
]
|
|
374
|
+
Curl::Multi.http(urls, {:pipeline => true}) do|easy, code, method|
|
|
375
|
+
assert_equal nil, code
|
|
376
|
+
case method
|
|
377
|
+
when :post
|
|
378
|
+
assert_match /POST/, easy.body_str
|
|
379
|
+
when :get
|
|
380
|
+
assert_match /GET/, easy.body_str
|
|
381
|
+
when :put
|
|
382
|
+
assert_match /PUT/, easy.body_str
|
|
383
|
+
end
|
|
384
|
+
#puts "#{easy.body_str.inspect}, #{method.inspect}, #{code.inspect}"
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def test_mutli_recieves_500
|
|
389
|
+
m = Curl::Multi.new
|
|
390
|
+
e = Curl::Easy.new("http://127.0.0.1:9129/methods")
|
|
391
|
+
failure = false
|
|
392
|
+
e.post_body = "hello=world&s=500"
|
|
393
|
+
e.on_failure{|c,r| failure = true }
|
|
394
|
+
e.on_success{|c| failure = false }
|
|
395
|
+
m.add(e)
|
|
396
|
+
m.perform
|
|
397
|
+
assert failure
|
|
398
|
+
e2 = Curl::Easy.new(TestServlet.url)
|
|
399
|
+
e2.post_body = "hello=world"
|
|
400
|
+
e2.on_failure{|c,r| failure = true }
|
|
401
|
+
m.add(e2)
|
|
402
|
+
m.perform
|
|
403
|
+
failure = false
|
|
404
|
+
assert !failure
|
|
405
|
+
assert_equal "POST\nhello=world", e2.body_str
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def test_remove_exception_is_descriptive
|
|
409
|
+
m = Curl::Multi.new
|
|
410
|
+
c = Curl::Easy.new("http://127.9.9.9:999110")
|
|
411
|
+
m.remove(c)
|
|
412
|
+
rescue => e
|
|
413
|
+
assert_equal 'Invalid easy handle', e.message
|
|
414
|
+
assert_equal 0, m.requests.size
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def test_retry_easy_handle
|
|
418
|
+
m = Curl::Multi.new
|
|
419
|
+
|
|
420
|
+
tries = 10
|
|
421
|
+
|
|
422
|
+
c1 = Curl::Easy.new('http://127.1.1.1:99911') do |curl|
|
|
423
|
+
curl.on_failure {|c,e|
|
|
424
|
+
assert_equal [Curl::Err::MalformedURLError, "URL using bad/illegal format or missing URL"], e
|
|
425
|
+
if tries > 0
|
|
426
|
+
tries -= 1
|
|
427
|
+
m.add(c)
|
|
428
|
+
end
|
|
429
|
+
}
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
tries -= 1
|
|
433
|
+
m.add(c1)
|
|
434
|
+
|
|
435
|
+
m.perform
|
|
436
|
+
assert_equal 0, tries
|
|
437
|
+
assert_equal 0, m.requests.size
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def test_reusing_handle
|
|
441
|
+
m = Curl::Multi.new
|
|
442
|
+
|
|
443
|
+
c = Curl::Easy.new('http://127.0.0.1') do|easy|
|
|
444
|
+
easy.on_complete{|e,r| puts e.inspect }
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
m.add(c)
|
|
448
|
+
m.add(c)
|
|
449
|
+
rescue => e
|
|
450
|
+
assert_equal Curl::Err::MultiBadEasyHandle, e.class
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def test_multi_default_timeout
|
|
454
|
+
assert_equal 100, Curl::Multi.default_timeout
|
|
455
|
+
Curl::Multi.default_timeout = 12
|
|
456
|
+
assert_equal 12, Curl::Multi.default_timeout
|
|
457
|
+
assert_equal 100, (Curl::Multi.default_timeout = 100)
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
include TestServerMethods
|
|
461
|
+
|
|
462
|
+
def setup
|
|
463
|
+
server_setup
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
end
|
data/tests/tc_curl_postfield.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'helper')
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
2
|
|
|
3
3
|
class TestCurbCurlPostfield < Test::Unit::TestCase
|
|
4
4
|
def test_private_new
|
|
@@ -62,6 +62,7 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
|
|
|
62
62
|
assert_equal 'foo', pf.name
|
|
63
63
|
assert_equal 'localname', pf.local_file
|
|
64
64
|
assert_equal 'localname', pf.remote_file
|
|
65
|
+
assert_nothing_raised { pf.to_s }
|
|
65
66
|
assert_nil pf.content_type
|
|
66
67
|
assert_nil pf.content
|
|
67
68
|
assert_nil pf.set_content_proc
|
|
@@ -136,6 +137,7 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
|
|
|
136
137
|
|
|
137
138
|
def test_to_s_04
|
|
138
139
|
pf = Curl::PostField.file('foo.file', 'bar.file')
|
|
139
|
-
|
|
140
|
+
assert_nothing_raised { pf.to_s }
|
|
141
|
+
#assert_raise(Curl::Err::InvalidPostFieldError) { pf.to_s }
|
|
140
142
|
end
|
|
141
143
|
end
|
data/tests/timeout.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
|
2
|
+
|
|
3
|
+
# Run server with: ruby -rubygems timeout_server.rb -p 9128
|
|
4
|
+
|
|
5
|
+
# Note that curl requires all timeouts to be integers -
|
|
6
|
+
# curl_easy_setopt does not have a provision for floating-point values
|
|
7
|
+
|
|
8
|
+
class TestCurbTimeouts < Test::Unit::TestCase
|
|
9
|
+
def test_no_timeout_by_default
|
|
10
|
+
curl = Curl::Easy.new(wait_url(2))
|
|
11
|
+
start = Time.now
|
|
12
|
+
assert_equal true, curl.http_get
|
|
13
|
+
elapsed = Time.now - start
|
|
14
|
+
assert elapsed > 2
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_overall_timeout_on_dead_transfer
|
|
18
|
+
curl = Curl::Easy.new(wait_url(2))
|
|
19
|
+
curl.timeout = 1
|
|
20
|
+
assert_raise(Curl::Err::TimeoutError) do
|
|
21
|
+
curl.http_get
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_clearing_timeout
|
|
26
|
+
curl = Curl::Easy.new(wait_url(2))
|
|
27
|
+
curl.timeout = 1
|
|
28
|
+
curl.timeout = nil
|
|
29
|
+
start = Time.now
|
|
30
|
+
assert_equal true, curl.http_get
|
|
31
|
+
elapsed = Time.now - start
|
|
32
|
+
assert elapsed > 2
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_overall_timeout_on_slow_transfer
|
|
36
|
+
curl = Curl::Easy.new(serve_url(100, 2, 3))
|
|
37
|
+
curl.timeout = 1
|
|
38
|
+
# transfer is aborted despite data being exchanged
|
|
39
|
+
assert_raise(Curl::Err::TimeoutError) do
|
|
40
|
+
curl.http_get
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_low_speed_time_on_slow_transfer
|
|
45
|
+
curl = Curl::Easy.new(serve_url(100, 1, 3))
|
|
46
|
+
curl.low_speed_time = 2
|
|
47
|
+
# use default low_speed_limit of 1
|
|
48
|
+
assert true, curl.http_get
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_low_speed_time_on_very_slow_transfer
|
|
52
|
+
# send data slower than required
|
|
53
|
+
curl = Curl::Easy.new(serve_url(10, 2, 3))
|
|
54
|
+
curl.low_speed_time = 1
|
|
55
|
+
# XXX for some reason this test fails if low speed limit is not specified
|
|
56
|
+
curl.low_speed_limit = 1
|
|
57
|
+
# use default low_speed_limit of 1
|
|
58
|
+
assert_raise(Curl::Err::TimeoutError) do
|
|
59
|
+
curl.http_get
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_low_speed_limit_on_slow_transfer
|
|
64
|
+
curl = Curl::Easy.new(serve_url(10, 1, 3))
|
|
65
|
+
curl.low_speed_time = 2
|
|
66
|
+
curl.low_speed_limit = 1000
|
|
67
|
+
assert_raise(Curl::Err::TimeoutError) do
|
|
68
|
+
curl.http_get
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_clearing_low_speed_time
|
|
73
|
+
curl = Curl::Easy.new(serve_url(100, 2, 3))
|
|
74
|
+
curl.low_speed_time = 1
|
|
75
|
+
curl.low_speed_time = nil
|
|
76
|
+
assert_equal true, curl.http_get
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_clearing_low_speed_limit
|
|
80
|
+
curl = Curl::Easy.new(serve_url(10, 1, 3))
|
|
81
|
+
curl.low_speed_time = 2
|
|
82
|
+
curl.low_speed_limit = 1000
|
|
83
|
+
curl.low_speed_limit = nil
|
|
84
|
+
assert_equal true, curl.http_get
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def wait_url(time)
|
|
90
|
+
"#{server_base}/wait/#{time}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def serve_url(chunk_size, time, count)
|
|
94
|
+
"#{server_base}/serve/#{chunk_size}/every/#{time}/for/#{count}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def server_base
|
|
98
|
+
'http://127.0.0.1:9128'
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# This Sinatra application must be run with mongrel
|
|
2
|
+
# or possibly with unicorn for the serve action to work properly.
|
|
3
|
+
# See http://efreedom.com/Question/1-3669674/Streaming-Data-Sinatra-Rack-Application
|
|
4
|
+
|
|
5
|
+
require 'sinatra'
|
|
6
|
+
|
|
7
|
+
get '/wait/:time' do |time|
|
|
8
|
+
time = time.to_i
|
|
9
|
+
sleep(time)
|
|
10
|
+
"Slept #{time} at #{Time.now}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# http://efreedom.com/Question/1-3027435/Way-Flush-Html-Wire-Sinatra
|
|
14
|
+
class Streamer
|
|
15
|
+
def initialize(time, chunks)
|
|
16
|
+
@time = time
|
|
17
|
+
@chunks = chunks
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def each
|
|
21
|
+
@chunks.each do |chunk|
|
|
22
|
+
sleep(@time)
|
|
23
|
+
yield chunk
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
get '/serve/:chunk_size/every/:time/for/:count' do |chunk_size, time, count|
|
|
29
|
+
chunk_size, time, count = chunk_size.to_i, time.to_i, count.to_i
|
|
30
|
+
chunk = 'x' * chunk_size
|
|
31
|
+
chunks = [chunk] * count
|
|
32
|
+
Streamer.new(time, chunks)
|
|
33
|
+
end
|