codders-curb 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.
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