curb 0.7.15 → 0.8.3

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,59 @@
1
1
  require 'curb'
2
+ require 'uri'
3
+
4
+ # expose shortcut methods
5
+ module Curl
6
+
7
+ def self.http(verb, url, post_body=nil, put_data=nil, &block)
8
+ handle = Curl::Easy.new(url)
9
+ handle.post_body = post_body if post_body
10
+ handle.put_data = put_data if put_data
11
+ yield handle if block_given?
12
+ handle.http(verb)
13
+ handle
14
+ end
15
+
16
+ def self.get(url, params={}, &block)
17
+ http :GET, urlalize(url, params), nil, nil, &block
18
+ end
19
+
20
+ def self.post(url, params={}, &block)
21
+ http :POST, url, postalize(params), nil, &block
22
+ end
23
+
24
+ def self.put(url, params={}, &block)
25
+ http :PUT, url, nil, postalize(params), &block
26
+ end
27
+
28
+ def self.delete(url, params={}, &block)
29
+ http :DELETE, url, postalize(params), nil, &block
30
+ end
31
+
32
+ def self.patch(url, params={}, &block)
33
+ http :PATCH, url, postalize(params), nil, &block
34
+ end
35
+
36
+ def self.head(url, params={}, &block)
37
+ http :OPTIONS, urlalize(url, params), nil, nil, &block
38
+ end
39
+
40
+ def self.options(url, params={}, &block)
41
+ http :OPTIONS, urlalize(url, params), nil, nil, &block
42
+ end
43
+
44
+ def self.urlalize(url, params={})
45
+ query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
46
+ if url.match(/\?/)
47
+ "#{url}&#{query_str}"
48
+ elsif query_str.size > 0
49
+ "#{url}?#{query_str}"
50
+ else
51
+ url
52
+ end
53
+ end
54
+
55
+ def self.postalize(params={})
56
+ params.respond_to?(:map) ? URI.encode_www_form(params) : (params.respond_to?(:to_s) ? params.to_s : params)
57
+ end
58
+
59
+ 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
data/tests/foo.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'curb'
2
+
3
+ SSL_CERT = '/path/to/my/cert'
4
+ SSL_KEY = '/path/to/my/key'
5
+
6
+ curl = Curl::Easy.new('98.129.21.125')
7
+ curl.verbose = true
8
+ curl.cert = SSL_CERT
9
+ curl.cert_key = SSL_KEY
10
+ curl.follow_location = true
11
+ curl.ssl_verify_host = false
12
+ curl.ssl_verify_peer = false
13
+ curl.perform
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
@@ -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
- assert !c.ssl_verify_host = false
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("#{$TEST_URL.gsub(/file:\/\//,'')}/not_here")
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,: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
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__,'r') do|f|
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
- curl.cert= File.join(File.dirname(__FILE__),"cert.pem:password")
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,54 @@ 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
+
991
+ def test_status_codes
992
+ curl = Curl::Easy.new(TestServlet.url)
993
+ curl.perform
994
+ assert_equal '200 OK', curl.status
995
+ end
996
+
997
+ def test_close_in_on_callbacks
998
+ curl = Curl::Easy.new(TestServlet.url)
999
+ curl.on_body {|d| curl.close; d.size }
1000
+ assert_raises RuntimeError do
1001
+ curl.perform
1002
+ end
1003
+ end
1004
+
891
1005
  include TestServerMethods
892
1006
 
893
1007
  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