curb 0.7.15 → 0.8.4

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/lib/curl.rb CHANGED
@@ -1 +1,62 @@
1
- require 'curb'
1
+ require 'curb_core'
2
+ require 'curl/easy'
3
+ require 'curl/multi'
4
+ require 'uri'
5
+
6
+ # expose shortcut methods
7
+ module Curl
8
+
9
+ def self.http(verb, url, post_body=nil, put_data=nil, &block)
10
+ handle = Thread.current[:curb_curl] ||= Curl::Easy.new
11
+ handle.url = url
12
+ handle.post_body = post_body if post_body
13
+ handle.put_data = put_data if put_data
14
+ yield handle if block_given?
15
+ handle.http(verb)
16
+ handle
17
+ end
18
+
19
+ def self.get(url, params={}, &block)
20
+ http :GET, urlalize(url, params), nil, nil, &block
21
+ end
22
+
23
+ def self.post(url, params={}, &block)
24
+ http :POST, url, postalize(params), nil, &block
25
+ end
26
+
27
+ def self.put(url, params={}, &block)
28
+ http :PUT, url, nil, postalize(params), &block
29
+ end
30
+
31
+ def self.delete(url, params={}, &block)
32
+ http :DELETE, url, postalize(params), nil, &block
33
+ end
34
+
35
+ def self.patch(url, params={}, &block)
36
+ http :PATCH, url, postalize(params), nil, &block
37
+ end
38
+
39
+ def self.head(url, params={}, &block)
40
+ http :HEAD, urlalize(url, params), nil, nil, &block
41
+ end
42
+
43
+ def self.options(url, params={}, &block)
44
+ http :OPTIONS, urlalize(url, params), nil, nil, &block
45
+ end
46
+
47
+ def self.urlalize(url, params={})
48
+ query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
49
+ if url.match(/\?/)
50
+ "#{url}&#{query_str}"
51
+ elsif query_str.size > 0
52
+ "#{url}?#{query_str}"
53
+ else
54
+ url
55
+ end
56
+ end
57
+
58
+ def self.postalize(params={})
59
+ params.respond_to?(:map) ? URI.encode_www_form(params) : (params.respond_to?(:to_s) ? params.to_s : params)
60
+ end
61
+
62
+ 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://127.0.0.1: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://127.0.0.1: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
@@ -21,7 +21,7 @@ class BugTestInstancePostDiffersFromClassPost < Test::Unit::TestCase
21
21
 
22
22
  5.times do |i|
23
23
  t = Thread.new do
24
- c = Curl::Easy.perform('http://localhost:9999/test')
24
+ c = Curl::Easy.perform('http://127.0.0.1:9999/test')
25
25
  c.header_str
26
26
  end
27
27
  threads << t
@@ -37,7 +37,7 @@ class BugTestInstancePostDiffersFromClassPost < Test::Unit::TestCase
37
37
  timer = Time.now
38
38
  single_responses = []
39
39
  5.times do |i|
40
- c = Curl::Easy.perform('http://localhost:9999/test')
40
+ c = Curl::Easy.perform('http://127.0.0.1:9999/test')
41
41
  single_responses << c.header_str
42
42
  end
43
43
 
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ class BugIssue102 < Test::Unit::TestCase
4
+
5
+ def test_interface
6
+ test = "https://api.twitter.com/1/users/show.json?screen_name=TwitterAPI&include_entities=true"
7
+ ip = "192.168.1.61"
8
+
9
+ c = Curl::Easy.new do |curl|
10
+ curl.url = test
11
+ curl.interface = ip
12
+ end
13
+
14
+ c.perform
15
+ end
16
+
17
+ end
@@ -24,7 +24,7 @@
24
24
  require 'test/unit'
25
25
  require 'rbconfig'
26
26
 
27
- $rubycmd = Config::CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
27
+ $rubycmd = RbConfig::CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
28
28
 
29
29
  class BugTestRequireLastOrSegfault < Test::Unit::TestCase
30
30
  def test_bug
data/tests/helper.rb CHANGED
@@ -65,12 +65,20 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
65
65
  end
66
66
 
67
67
  def do_GET(req,res)
68
- respond_with(: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
76
+ respond_with("GET#{req.query_string}",req,res)
69
77
  end
70
78
 
71
79
  def do_HEAD(req,res)
72
80
  res['Location'] = "/nonexistent"
73
- respond_with(:HEAD, req, res)
81
+ respond_with("HEAD#{req.query_string}",req,res)
74
82
  end
75
83
 
76
84
  def do_POST(req,res)
@@ -95,15 +103,23 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
95
103
  end
96
104
 
97
105
  def do_DELETE(req,res)
98
- respond_with(:DELETE,req,res)
106
+ respond_with("DELETE#{req.query_string}",req,res)
99
107
  end
100
108
 
101
109
  def do_PURGE(req,res)
102
- respond_with(:PURGE,req,res)
110
+ respond_with("PURGE#{req.query_string}",req,res)
103
111
  end
104
112
 
105
113
  def do_COPY(req,res)
106
- respond_with(:COPY,req,res)
114
+ respond_with("COPY#{req.query_string}",req,res)
115
+ end
116
+
117
+ def do_PATCH(req,res)
118
+ respond_with("PATCH\n#{req.body}",req,res)
119
+ end
120
+
121
+ def do_OPTIONS(req,res)
122
+ respond_with("OPTIONS#{req.query_string}",req,res)
107
123
  end
108
124
 
109
125
  end
data/tests/signals.rb ADDED
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ # This test suite requires the timeout server to be running
4
+ # See tests/timeout.rb for more info about the timeout server
5
+ class TestCurbSignals < Test::Unit::TestCase
6
+
7
+ # Testcase for https://github.com/taf2/curb/issues/117
8
+ def test_continue_after_signal
9
+ trap("SIGUSR1") { }
10
+
11
+ curl = Curl::Easy.new(wait_url(2))
12
+ pid = $$
13
+ Thread.new do
14
+ sleep 1
15
+ Process.kill("SIGUSR1", pid)
16
+ end
17
+ assert_equal true, curl.http_get
18
+ end
19
+
20
+ private
21
+
22
+ def wait_url(time)
23
+ "#{server_base}/wait/#{time}"
24
+ end
25
+
26
+ def serve_url(chunk_size, time, count)
27
+ "#{server_base}/serve/#{chunk_size}/every/#{time}/for/#{count}"
28
+ end
29
+
30
+ def server_base
31
+ 'http://127.0.0.1:9128'
32
+ end
33
+ end
data/tests/tc_curl.rb ADDED
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ class TestCurl < Test::Unit::TestCase
4
+ def test_get
5
+ curl = Curl.get(TestServlet.url, {:foo => "bar"})
6
+ assert_equal "GETfoo=bar", curl.body_str
7
+
8
+ curl = Curl.options(TestServlet.url, {:foo => "bar"}) do|http|
9
+ http.headers['Cookie'] = 'foo=1;bar=2'
10
+ end
11
+ assert_equal "OPTIONSfoo=bar", curl.body_str
12
+ end
13
+
14
+ def test_post
15
+ curl = Curl.post(TestServlet.url, {:foo => "bar"})
16
+ assert_equal "POST\nfoo=bar", curl.body_str
17
+ end
18
+
19
+ def test_put
20
+ curl = Curl.put(TestServlet.url, {:foo => "bar"})
21
+ assert_equal "PUT\nfoo=bar", curl.body_str
22
+ end
23
+
24
+ def test_patch
25
+ curl = Curl.patch(TestServlet.url, {:foo => "bar"})
26
+ assert_equal "PATCH\nfoo=bar", curl.body_str
27
+ end
28
+
29
+ def test_options
30
+ curl = Curl.options(TestServlet.url, {:foo => "bar"})
31
+ assert_equal "OPTIONSfoo=bar", curl.body_str
32
+ end
33
+
34
+ include TestServerMethods
35
+
36
+ def setup
37
+ server_setup
38
+ end
39
+ end
@@ -4,6 +4,21 @@ class FooNoToS
4
4
  end
5
5
 
6
6
  class TestCurbCurlEasy < Test::Unit::TestCase
7
+ def test_threads
8
+ t = []
9
+ 5.times do
10
+ t << Thread.new do
11
+ 5.times do
12
+ c = Curl.get($TEST_URL)
13
+ assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
14
+ assert_equal "", c.header_str
15
+ end
16
+ end
17
+ end
18
+
19
+ t.each {|t| t.join }
20
+ end
21
+
7
22
  def test_class_perform_01
8
23
  assert_instance_of Curl::Easy, c = Curl::Easy.perform($TEST_URL)
9
24
  assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
@@ -461,7 +476,8 @@ class TestCurbCurlEasy < Test::Unit::TestCase
461
476
  def test_ssl_verify_host
462
477
  c = Curl::Easy.new
463
478
  assert c.ssl_verify_host?
464
- assert !c.ssl_verify_host = false
479
+ c.ssl_verify_host = 0
480
+ c.ssl_verify_host = false
465
481
  assert !c.ssl_verify_host?
466
482
  end
467
483
 
@@ -507,6 +523,17 @@ class TestCurbCurlEasy < Test::Unit::TestCase
507
523
  assert c.ignore_content_length?
508
524
  end
509
525
 
526
+ def test_resolve_mode
527
+ c = Curl::Easy.new
528
+ assert_equal :auto, c.resolve_mode
529
+ c.resolve_mode = :ipv4
530
+ assert_equal :ipv4, c.resolve_mode
531
+ c.resolve_mode = :ipv6
532
+ assert_equal :ipv6, c.resolve_mode
533
+
534
+ assert_raises(ArgumentError) { c.resolve_mode = :bad }
535
+ end
536
+
510
537
  def test_enable_cookies
511
538
  c = Curl::Easy.new
512
539
  assert !c.enable_cookies?
@@ -549,13 +576,34 @@ class TestCurbCurlEasy < Test::Unit::TestCase
549
576
  end
550
577
 
551
578
  def test_on_success_with_on_failure
552
- curl = Curl::Easy.new("#{$TEST_URL.gsub(/file:\/\//,'')}/not_here")
579
+ curl = Curl::Easy.new(TestServlet.url + '/error')
553
580
  on_failure_called = false
554
581
  curl.on_success {|c| } # make sure we get the failure call even though this handler is defined
555
582
  curl.on_failure {|c,code| on_failure_called = true }
556
583
  curl.perform
584
+ assert_equal 500, curl.response_code
557
585
  assert on_failure_called, "Failure handler not called"
558
586
  end
587
+
588
+ def test_on_success_with_on_missing
589
+ curl = Curl::Easy.new(TestServlet.url + '/not_here')
590
+ on_missing_called = false
591
+ curl.on_success {|c| } # make sure we get the missing call even though this handler is defined
592
+ curl.on_missing {|c,code| on_missing_called = true }
593
+ curl.perform
594
+ assert_equal 404, curl.response_code
595
+ assert on_missing_called, "Missing handler not called"
596
+ end
597
+
598
+ def test_on_success_with_on_redirect
599
+ curl = Curl::Easy.new(TestServlet.url + '/redirect')
600
+ on_redirect_called = false
601
+ curl.on_success {|c| } # make sure we get the redirect call even though this handler is defined
602
+ curl.on_redirect {|c,code| on_redirect_called = true }
603
+ curl.perform
604
+ assert_equal 302, curl.response_code
605
+ assert on_redirect_called, "Redirect handler not called"
606
+ end
559
607
 
560
608
  def test_get_remote
561
609
  curl = Curl::Easy.new(TestServlet.url)
@@ -572,15 +620,35 @@ class TestCurbCurlEasy < Test::Unit::TestCase
572
620
  def test_post_remote_is_easy_handle
573
621
  # see: http://pastie.org/560852 and
574
622
  # http://groups.google.com/group/curb---ruby-libcurl-bindings/browse_thread/thread/216bb2d9b037f347?hl=en
575
- [:post, :get,:head,:delete].each do |method|
576
- count = 0
577
- curl = Curl::Easy.send("http_#{method}", TestServlet.url) do|c|
578
- count += 1
579
- assert_equal Curl::Easy, c.class
623
+ [:post, :get, :head, :delete].each do |method|
624
+ retries = 0
625
+ begin
626
+ count = 0
627
+ curl = Curl::Easy.send("http_#{method}", TestServlet.url) do|c|
628
+ count += 1
629
+ assert_equal Curl::Easy, c.class
630
+ end
631
+ assert_equal 1, count, "For request method: #{method.to_s.upcase}"
632
+ rescue Curl::Err::HostResolutionError => e # travis-ci.org fails to resolve... try again?
633
+ retries+=1
634
+ retry if retries < 3
635
+ raise e
580
636
  end
581
- assert_equal 1, count, "For request method: #{method.to_s.upcase}"
582
637
  end
583
638
  end
639
+
640
+ # see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
641
+ def test_post_multipart_array_remote
642
+ curl = Curl::Easy.new(TestServlet.url)
643
+ curl.multipart_form_post = true
644
+ fields = [
645
+ Curl::PostField.file('foo', File.expand_path(File.join(File.dirname(__FILE__),'..','README'))),
646
+ Curl::PostField.file('bar', File.expand_path(File.join(File.dirname(__FILE__),'..','README')))
647
+ ]
648
+ curl.http_post(fields)
649
+ assert_match /HTTP POST file upload/, curl.body_str
650
+ assert_match /Content-Disposition: form-data/, curl.body_str
651
+ end
584
652
 
585
653
  def test_post_with_body_remote
586
654
  curl = Curl::Easy.new(TestServlet.url)
@@ -664,6 +732,17 @@ class TestCurbCurlEasy < Test::Unit::TestCase
664
732
  assert_match /message$/, curl.body_str
665
733
  end
666
734
 
735
+ # https://github.com/taf2/curb/issues/101
736
+ def test_put_data_null_bytes
737
+ curl = Curl::Easy.new(TestServlet.url)
738
+ curl.put_data = "a\0b"
739
+
740
+ curl.perform
741
+
742
+ assert_match /^PUT/, curl.body_str
743
+ assert_match "a\0b", curl.body_str
744
+ end
745
+
667
746
  def test_put_nil_data_no_crash
668
747
  curl = Curl::Easy.new(TestServlet.url)
669
748
  curl.put_data = nil
@@ -673,7 +752,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
673
752
 
674
753
  def test_put_remote_file
675
754
  curl = Curl::Easy.new(TestServlet.url)
676
- File.open(__FILE__,'r') do|f|
755
+ File.open(__FILE__,'rb') do|f|
677
756
  assert curl.http_put(f)
678
757
  end
679
758
  assert_equal "PUT\n#{File.read(__FILE__)}", curl.body_str
@@ -700,7 +779,9 @@ class TestCurbCurlEasy < Test::Unit::TestCase
700
779
 
701
780
  def test_cert_with_password
702
781
  curl = Curl::Easy.new(TestServlet.url)
703
- curl.cert= File.join(File.dirname(__FILE__),"cert.pem:password")
782
+ path = File.join(File.dirname(__FILE__),"cert.pem")
783
+ curl.certpassword = 'password'
784
+ curl.cert = path
704
785
  assert_match /cert.pem$/,curl.cert
705
786
  end
706
787
 
@@ -888,6 +969,54 @@ class TestCurbCurlEasy < Test::Unit::TestCase
888
969
 
889
970
  end
890
971
 
972
+ def test_get_set_multi_on_easy
973
+ easy = Curl::Easy.new
974
+ assert_nil easy.multi
975
+ multi = Curl::Multi.new
976
+ easy.multi = multi
977
+ assert_not_nil easy.multi
978
+ assert_equal multi, easy.multi
979
+ end
980
+
981
+ def test_raise_on_progress
982
+ c = Curl::Easy.new($TEST_URL)
983
+ c.on_progress {|w,x,y,z| raise "error" }
984
+ c.perform
985
+ rescue => e
986
+ assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
987
+ c.close
988
+ end
989
+
990
+ def test_raise_on_success
991
+ c = Curl::Easy.new($TEST_URL)
992
+ c.on_success {|x| raise "error" }
993
+ c.perform
994
+ rescue => e
995
+ assert_equal 'Curl::Err::AbortedByCallbackError', e.class.to_s
996
+ c.close
997
+ end
998
+
999
+ def test_raise_on_debug
1000
+ c = Curl::Easy.new($TEST_URL)
1001
+ c.on_debug { raise "error" }
1002
+ c.perform
1003
+ assert true, "raise in on debug has no effect"
1004
+ end
1005
+
1006
+ def test_status_codes
1007
+ curl = Curl::Easy.new(TestServlet.url)
1008
+ curl.perform
1009
+ assert_equal '200 OK', curl.status
1010
+ end
1011
+
1012
+ def test_close_in_on_callbacks
1013
+ curl = Curl::Easy.new(TestServlet.url)
1014
+ curl.on_body {|d| curl.close; d.size }
1015
+ assert_raises RuntimeError do
1016
+ curl.perform
1017
+ end
1018
+ end
1019
+
891
1020
  include TestServerMethods
892
1021
 
893
1022
  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
@@ -385,7 +385,26 @@ class TestCurbCurlMulti < Test::Unit::TestCase
385
385
  end
386
386
  end
387
387
 
388
- def test_mutli_recieves_500
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
389
408
  m = Curl::Multi.new
390
409
  e = Curl::Easy.new("http://127.0.0.1:9129/methods")
391
410
  failure = false
@@ -410,7 +429,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
410
429
  c = Curl::Easy.new("http://127.9.9.9:999110")
411
430
  m.remove(c)
412
431
  rescue => e
413
- assert_equal 'Invalid easy handle', e.message
432
+ assert_equal 'CURLError: Invalid easy handle', e.message
414
433
  assert_equal 0, m.requests.size
415
434
  end
416
435