codders-curb 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/LICENSE +51 -0
  2. data/README +194 -0
  3. data/Rakefile +320 -0
  4. data/doc.rb +42 -0
  5. data/ext/curb.c +977 -0
  6. data/ext/curb.h +52 -0
  7. data/ext/curb_easy.c +3404 -0
  8. data/ext/curb_easy.h +90 -0
  9. data/ext/curb_errors.c +647 -0
  10. data/ext/curb_errors.h +129 -0
  11. data/ext/curb_macros.h +159 -0
  12. data/ext/curb_multi.c +633 -0
  13. data/ext/curb_multi.h +26 -0
  14. data/ext/curb_postfield.c +523 -0
  15. data/ext/curb_postfield.h +40 -0
  16. data/ext/curb_upload.c +80 -0
  17. data/ext/curb_upload.h +30 -0
  18. data/ext/extconf.rb +399 -0
  19. data/lib/curb.rb +4 -0
  20. data/lib/curl.rb +57 -0
  21. data/lib/curl/easy.rb +468 -0
  22. data/lib/curl/multi.rb +248 -0
  23. data/tests/alltests.rb +3 -0
  24. data/tests/bug_crash_on_debug.rb +39 -0
  25. data/tests/bug_crash_on_progress.rb +33 -0
  26. data/tests/bug_curb_easy_blocks_ruby_threads.rb +52 -0
  27. data/tests/bug_curb_easy_post_with_string_no_content_length_header.rb +83 -0
  28. data/tests/bug_instance_post_differs_from_class_post.rb +53 -0
  29. data/tests/bug_multi_segfault.rb +14 -0
  30. data/tests/bug_postfields_crash.rb +26 -0
  31. data/tests/bug_postfields_crash2.rb +57 -0
  32. data/tests/bug_require_last_or_segfault.rb +40 -0
  33. data/tests/bugtests.rb +9 -0
  34. data/tests/helper.rb +199 -0
  35. data/tests/mem_check.rb +65 -0
  36. data/tests/require_last_or_segfault_script.rb +36 -0
  37. data/tests/tc_curl_download.rb +75 -0
  38. data/tests/tc_curl_easy.rb +1011 -0
  39. data/tests/tc_curl_easy_setopt.rb +31 -0
  40. data/tests/tc_curl_multi.rb +485 -0
  41. data/tests/tc_curl_postfield.rb +143 -0
  42. data/tests/timeout.rb +100 -0
  43. data/tests/timeout_server.rb +33 -0
  44. data/tests/unittests.rb +2 -0
  45. metadata +133 -0
@@ -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
@@ -0,0 +1,485 @@
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_multi_easy_http_with_max_connects
389
+ urls = [
390
+ { :url => TestServlet.url + '?q=1', :method => :get },
391
+ { :url => TestServlet.url + '?q=2', :method => :get },
392
+ { :url => TestServlet.url + '?q=3', :method => :get }
393
+ ]
394
+ Curl::Multi.http(urls, {:pipeline => true, :max_connects => 1}) do|easy, code, method|
395
+ assert_equal nil, code
396
+ case method
397
+ when :post
398
+ assert_match /POST/, easy.body_str
399
+ when :get
400
+ assert_match /GET/, easy.body_str
401
+ when :put
402
+ assert_match /PUT/, easy.body_str
403
+ end
404
+ end
405
+ end
406
+
407
+ def test_multi_recieves_500
408
+ m = Curl::Multi.new
409
+ e = Curl::Easy.new("http://127.0.0.1:9129/methods")
410
+ failure = false
411
+ e.post_body = "hello=world&s=500"
412
+ e.on_failure{|c,r| failure = true }
413
+ e.on_success{|c| failure = false }
414
+ m.add(e)
415
+ m.perform
416
+ assert failure
417
+ e2 = Curl::Easy.new(TestServlet.url)
418
+ e2.post_body = "hello=world"
419
+ e2.on_failure{|c,r| failure = true }
420
+ m.add(e2)
421
+ m.perform
422
+ failure = false
423
+ assert !failure
424
+ assert_equal "POST\nhello=world", e2.body_str
425
+ end
426
+
427
+ def test_remove_exception_is_descriptive
428
+ m = Curl::Multi.new
429
+ c = Curl::Easy.new("http://127.9.9.9:999110")
430
+ m.remove(c)
431
+ rescue => e
432
+ assert_equal 'Invalid easy handle', e.message
433
+ assert_equal 0, m.requests.size
434
+ end
435
+
436
+ def test_retry_easy_handle
437
+ m = Curl::Multi.new
438
+
439
+ tries = 10
440
+
441
+ c1 = Curl::Easy.new('http://127.1.1.1:99911') do |curl|
442
+ curl.on_failure {|c,e|
443
+ assert_equal [Curl::Err::MalformedURLError, "URL using bad/illegal format or missing URL"], e
444
+ if tries > 0
445
+ tries -= 1
446
+ m.add(c)
447
+ end
448
+ }
449
+ end
450
+
451
+ tries -= 1
452
+ m.add(c1)
453
+
454
+ m.perform
455
+ assert_equal 0, tries
456
+ assert_equal 0, m.requests.size
457
+ end
458
+
459
+ def test_reusing_handle
460
+ m = Curl::Multi.new
461
+
462
+ c = Curl::Easy.new('http://127.0.0.1') do|easy|
463
+ easy.on_complete{|e,r| puts e.inspect }
464
+ end
465
+
466
+ m.add(c)
467
+ m.add(c)
468
+ rescue => e
469
+ assert_equal Curl::Err::MultiBadEasyHandle, e.class
470
+ end
471
+
472
+ def test_multi_default_timeout
473
+ assert_equal 100, Curl::Multi.default_timeout
474
+ Curl::Multi.default_timeout = 12
475
+ assert_equal 12, Curl::Multi.default_timeout
476
+ assert_equal 100, (Curl::Multi.default_timeout = 100)
477
+ end
478
+
479
+ include TestServerMethods
480
+
481
+ def setup
482
+ server_setup
483
+ end
484
+
485
+ end